home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Mathematics / Notebooks / SigProc2.0 / Packages / SignalProcessing / Support / SigProc.m < prev    next >
Encoding:
Text File  |  1992-08-18  |  82.5 KB  |  2,452 lines

  1. (*  :Title:    Signal Processing Primitive Objects  *)
  2.  
  3. (*  :Authors:    Brian Evans, James McClellan  *)
  4.  
  5. (*
  6.     :Summary:   Provide functions which are common in DSP but
  7.         not standard in Mathematica.  Functions like
  8.         Step and Impulse, as well as operators like
  9.         Upsample and Shift.
  10.  *)
  11.  
  12. (*  :Context:    SignalProcessing`Support`SigProc`  *)
  13.  
  14. (*  :PackageVersion:  2.7    *)
  15.  
  16. (*
  17.     :Copyright:    Copyright 1989-1991 by Brian L. Evans
  18.         Georgia Tech Research Corporation
  19.  
  20.     Permission to use, copy, modify, and distribute this software
  21.     and its documentation for any purpose and without fee is
  22.     hereby granted, provided that the above copyright notice
  23.     appear in all copies and that both that copyright notice and
  24.     this permission notice appear in supporting documentation,
  25.     and that the name of the Georgia Tech Research Corporation,
  26.     Georgia Tech, or Georgia Institute of Technology not be used
  27.     in advertising or publicity pertaining to distribution of the
  28.     software without specific, written prior permission.  Georgia
  29.     Tech makes no representations about the suitability of this
  30.     software for any purpose.  It is provided "as is" without
  31.     express or implied warranty.
  32.  *)
  33.  
  34. (*  :History:    signal processing, operators, functions, symbolic processing *)
  35.  
  36. (*  :Keywords:    *)
  37.  
  38. (*
  39.     :Source:         Oppenheim, A., and Schafer, R.  {Discrete-Time
  40.         Signal Processing}.  1989.
  41.     
  42.              Myers, C.  {Signal Representation for Symbolic and
  43.         Numeric Processing}.  MIT Ph.D. Thesis.  1986.
  44.  
  45.              Covell, M.  {An Algorithm Design Environment}.
  46.         MIT Ph. D. Thesis, 1989.
  47.  
  48.              Bamberger, R. {The Directional Filter Bank:  A Multirate
  49.         Filter Bank for the Directional Decompostion of Images},
  50.         Georgia Tech Ph. D. Thesis, 1990.
  51.  *)
  52.  
  53. (*  :Warning:    *)
  54.  
  55. (*  :Mathematica Version:  1.2 or 2.0  *)
  56.  
  57. (*  :Limitation:  *)
  58.  
  59. (*
  60.     :Discussion:    This package introduces the functions (signals) and
  61.           operators (systems) common in signal processing but missing
  62.           in Mathematica.
  63.             Thanks to John Mitchell at the University of Chicago
  64.           for writing patches for the Summation operator and the Delta
  65.           function.
  66. *)
  67.  
  68. (*  :Functions: Aliasby            operator
  69.         AliasSinc        alias
  70.         ASinc            alias
  71.         CConvolve        operator
  72.         CircularShift        operator
  73.         Convolve        operator
  74.         Continuous        option value
  75.         CPulse            function
  76.         CStep            function
  77.         Delta            function
  78.         DeltaPlot        function
  79.         DFT            operator
  80.         DTFT            operator
  81.         Discrete        option value
  82.         Difference        operator
  83.         Dirichlet        function
  84.         DiscreteGraphics    routine
  85.         Domain            option
  86.         Downsample        operator
  87.         DummyVariables        function
  88.         Extent1D        function
  89.         FT            operator
  90.         GetDeltaFunctions    function
  91.         Impulse            function
  92.         Interleave        operator
  93.         IntervalsToFunction    routine
  94.         InvDFT            operator
  95.         InvFT            operator
  96.         InvL            operator
  97.         InvZ            operator
  98.         L            operator
  99.         LineImpulse        function
  100.         OperatorInOperExpr    routine
  101.         OperatorName        routine
  102.         ParametersInOperExpr    routine
  103.         PolyphaseDownsample    operator
  104.         PolyphaseUpsample    operator
  105.         Periodic        operator
  106.         Pulse            function
  107.         RationalGCD        routine
  108.         Rev            operator
  109.         RewriteSummations    routine
  110.         ScaleAxis        operator
  111.         ScalingFactor        routine
  112.         SequenceToFunction    routine
  113.         SequencePlot        routine
  114.         Shift            operator
  115.         SignalCleanup        routine
  116.         SignalPlot        function
  117.         SignalsInOperExpr    routine
  118.         Sinc            function
  119.         SPSimplify        function
  120.         Step            function
  121.         Summation        operator
  122.         TheFunction        routine
  123.         ToContinuous        routine
  124.         ToDiscrete        routine
  125.         Unit            function
  126.         Upsample        operator
  127.         UpsampledFunction    routine
  128.         UpsampleFactor        routine
  129.         UpsampleSequence    routine
  130.         Z            operator
  131.  
  132.     This package provides signal primitives (functions), system
  133.     primitives (operators), and supporting routines.   Each new
  134.     object is placed into the SPsignals, SPsystems, or SPfunctions
  135.     list accordingly (at end of file).
  136.     
  137.     Each signal primitive (function) is specified as follows:
  138.  
  139.     (1) default arguments (if any),
  140.     (2) definition (so that it behaves as a function),
  141.     (3) multidimensional separability (if any),
  142.     (4) automatic simplification rules,
  143.     (5) manual simplification rules (augment Simplify),
  144.     (6) output form rules (including TeX form rules), and
  145.     (7) derivative and integration rules (if any)
  146.  
  147.     Each system primitive (operator) is specified as follows:
  148.  
  149.     (1) multidimensional separability (if any),
  150.     (2) manual simplification rules (augment Simplify),
  151.     (3) definition (so that it can be converted into a function form),
  152.     (4) output form rules (including TeX form rules), and
  153.     (5) specify which parameter is (are) the variable(s)
  154.  *)
  155.  
  156.  
  157.  
  158. (*  B E G I N     P A C K A G E  *)
  159.  
  160. BeginPackage[ "SignalProcessing`Support`SigProc`",
  161.           "SignalProcessing`Support`SupCode`" ]
  162.  
  163.  
  164. If [ TrueQ[ $VersionNumber >= 2.0 ],
  165.      Off[ General::spell ];
  166.      Off[ General::spell1 ] ]
  167.  
  168.  
  169. (*  U S A G E     I N F O R M A T I O N  *)
  170.  
  171. $DeltaFunctionScaling::usage =
  172.     "The variable $DeltaFunctionScaling dictates how to scale the heighth \
  173.     of Delta functions for the purposes of plotting:  None or Scaled."
  174.  
  175. Aliasby::usage =
  176.     "Aliasby[m,w][x] represents the aliasing of x, a continuous-frequency \
  177.     signal, by replicating it every (2 Pi / m) in w and dividing the \
  178.     result by m. \
  179.     It is always rewritten in terms of the Periodic operator."
  180.  
  181. CConvolve::usage =
  182.     "CConvolve[t][x1, x2, ...] represents the continuous convolution in t \
  183.     of functions x1, x2, .... \
  184.     CConvolve[{t1, t2, ...}][x1, x2, ...] represents the multidimensional \
  185.     continuous convolution in t1, t2, ... of functions x1, x2, ..."
  186.  
  187. CircularShift::usage =
  188.     "CircularShift[n0, N, n] represents the circular shifting of a \
  189.     sequence of length N in index variable n by n0. \
  190.     That is, the sequence is treated as a ring buffer of length N \
  191.     so each sample at index n is shifted to the right by
  192.     (n + n0) mod N places. \
  193.     See also Shift and RotateRight."
  194.  
  195. Convolve::usage =
  196.     "Convolve[n][x1, x2, ...] represents the discrete convolution in n of \
  197.     functions x1, x2, .... \
  198.     Convolve[{n1, n2, ...}][x1, x2, ...] represents the multidimensional \
  199.     discrete convolution in n1, n2, ... of functions x1, x2, ..."
  200.  
  201. Continuous::usage =
  202.     "Continuous is a possible value for a signal's domain."
  203.  
  204. CPulse::usage = 
  205.     "CPulse[l,t] defines a pulse which begins at t=0 and ends at t = l. \
  206.     The CPulse has value 1 within the range (0,l), \
  207.     0 outside this range, and 1/2 at the points t=0 and t=l. \
  208.     A continuous-pulse center at the origin is written as \
  209.     CPulse[l, t + l/2] or Shift[-l/2, t][CPulse[l, t]]."
  210.  
  211. CStep::usage =
  212.     "CStep[t], a.k.a. Unit[-1][t], is the unit step function \
  213.     which is 1 for t > 0, 0 for t < 0, and 1/2 at t = 0. \
  214.     It is commonly used for continuous expressions t. \
  215.     See also Step and Unit."
  216.  
  217. Delta::usage =
  218.     "Delta[expr] is the Dirac delta function. \
  219.     The area under this functions is 1 but it only has value \
  220.     at the origin. \
  221.     That is, Integrate[ Delta[t] g[t], {t, t1, t2} ] is g[0] \
  222.     if t1 <= 0 <= t2, 0 otherwise. \
  223.     It differs from the Kronecker delta function Impulse[t]."
  224.  
  225. DeltaIntegrate::usage =
  226.     "DeltaIntegrate[fun, {x, xlower, xupper}] and DeltaIntegrate[fun, x] \
  227.     are special hooks for the built-in Integrate routine."
  228.  
  229. DeltaPlot::usage =
  230.     "DeltaPlot is a object that can generate a plot of only Dirac delta \
  231.     functions or a combination of Dirac delta functions and another plot. \
  232.     In the first case, either four or six arguments are passed: \
  233.     deltafuns, t, tmin, tmax, ymin, ymax.\
  234.     In the second case, either five or seven arguments are passed: \
  235.     deltafuns, t, tmin, tmax, plot, ymin, ymax. \
  236.     In both cases, ymin and ymax are the optional arguments. \
  237.     DeltaPlot returns a list of plots suitable for sending to Show. \
  238.     Note that 1-D Delta functions are plotted as arrows. \
  239.     The variable $DeltaFunctionScaling dictates how Delta functions \
  240.     are scaled when plotted:  None or Scaled."
  241.  
  242. DFT::usage =
  243.     "DFT[L, n, k] is the forward discrete Fourier transform operator. \
  244.     Here, L is the DFT length(s), n is the time-domain variable(s), and \
  245.     k is the frequency-domain variable(s). \
  246.     Multidimensional DFT's are supported. \
  247.     Applying TheFunction to the DFT operator will invoke \
  248.     the DFT rule base (object DFTransform) if loaded."
  249.  
  250. DTFT::usage =
  251.     "DTFT[n, w] is the forward discrete-time Fourier transform operator. \
  252.     Here, n is the time-domain variable(s), and w is the frequency-domain \
  253.     variable(s). \
  254.     Multidimensional DTFT's are supported. \
  255.     Applying TheFunction to the DTFT operator will invoke the DTFT \
  256.     rule base (object DTFTransform) if loaded."
  257.  
  258. Difference::usage =
  259.     "Difference[k,n] represents the k-th backward difference with respect \
  260.     to the variable n. \
  261.     The first-order difference of f equals f[n] - f[n-1], \
  262.     the second-order difference is f[n] - 2 f[n-1] + f[n-2], and so on. \
  263.     Applying this operator to the sequence x[n] would be written as \
  264.     Difference[k,n][ x[n] ]."
  265.  
  266. Dirichlet::usage =
  267.     "Dirichlet[N, w] is the aliased sinc function. \
  268.     which is defined as Sin[N w / 2] / ( N Sin [w / 2] ). \
  269.     Aliases for Dirichlet are ASinc, AliasSinc, and AliasedSinc."
  270.  
  271. Discrete::usage =
  272.     "Discrete is a possible value for a signal's domain."
  273.  
  274. DiscreteGraphics::usage =
  275.     "DiscreteGraphics[{{x1,y1}, {x2,y2}, ... {xN,yN}}] will plot \
  276.     the points as lines drawn from the x-axis to the y-value. \
  277.     It takes two optional arguments:  a line thickness and \
  278.     a point thickness. \
  279.     Each is a real value from 0 to 1 indicating a width that \
  280.     is a fraction of the size of the entire graph."
  281.  
  282. Domain::usage =
  283.     "Domain is an option for many signal processing functions. \
  284.     It is either Discrete or Continuous."
  285.  
  286. Downsample::usage =
  287.     "Downsample[m,n] represents the downsampling operator. \
  288.     Downsampling resamples a function at the points n = 0, m, 2m, 3m, ... \
  289.     In N dimensions, n is a list of N indices and m is an N x N matrix. \
  290.     Applying TheFunction to f[n] which is downsampled in one dimension, \
  291.     (written as Downsample[m, n][ f[n] ]) will produce f[m n]."
  292.  
  293. DummyVariables::usage =
  294.     "DummyVariables[dimension, variable] generates dimension dummy \
  295.     variables with variable as the root. \
  296.     For example, n can be generated by DummyVariables[1, n] or \
  297.     DummyVariables[0, n]. \
  298.     As another example, DummyVariables[3, t] returns {t1, t2, t3}. \
  299.     In this cases, the generated variables have the same context \
  300.     as variable. \
  301.     DummyVariables[dimension, variable, context] can \
  302.     be used to specify another context/package."
  303.  
  304. Extent1D::usage =
  305.     "Extent1D[expression, var] returns an interval \
  306.     {lower-limit, upper-limit} outside of which the function is zero. \
  307.     This routine assumes that var is a real variable."
  308.  
  309. FT::usage =
  310.     "FT[t, w] is the forward continuous Fourier transform operator. \
  311.     Here, t is the time-domain variable(s) and w is the \
  312.     frequency-domain variable(s). \
  313.     Applying TheFunction to this operator will invoke the continuous-time \
  314.     Fourier transform rule base (object CTFTransform) if loaded."
  315.  
  316. GetDeltaFunctions::usage =
  317.     "GetDeltaFunctions[function, variable(s)] will extract \
  318.     all delta functions from the argument function.  See also DeltaPlot."
  319.  
  320. Impulse::usage =
  321.     "Impulse[n] is the unit Kronecker Delta function. \
  322.     At n = 0, the function evaluates to 1. \
  323.     Elsewhere, it evaluates to 0."
  324.  
  325. Interleave::usage =
  326.     "Interleave[n][x0, x1, ...] interleaves samples of signals \
  327.     x0, x1, ..., which are functions of n. \
  328.     This is only applicable to discrete signals."
  329.  
  330. IntervalsToFunction::usage =
  331.     "IntervalsToFunction[interlist, n, step, pulse] \
  332.     will translate the list of functions and intervals (interlist) \
  333.     into a signal expression as a function of n. \
  334.     Each element in the interlist is a list of three elements: \
  335.     <function_of_n>, <n_minus>, and <n_plus>. \
  336.     The function <function_of_n> will be defined for \
  337.     <n_minus> <= n <= <n_plus>. \
  338.     Note that <n_minus> can be an integer or -Infinity and \
  339.     that <n_plus> can be an integer or Infinity. \
  340.     The default values are n = Global`n, \
  341.     step = Step, and pulse = Pulse. \
  342.     This function also works for when n represents a continuous variable \
  343.     (step = CStep and pulse = CPulse)."
  344.  
  345. InvDFT::usage =
  346.     "InvDFT[L, k, n] is the inverse discrete Fourier transform operator. \
  347.     Here, L is the DFT length(s), n is the time-domain variable(s), and \
  348.     k is the frequency-domain variable(s). \
  349.     Multidimensional inverse DFT's are supported. \
  350.     Applying TheFunction to the InvDFT operator will invoke the \
  351.     inverse DFT rule base (object InvDFTransform) if loaded."
  352.  
  353. InvDTFT::usage =
  354.     "InvDTFT[w, n] is the inverse discrete-time Fourier transform \
  355.     operator. \
  356.     Here, n is the time-domain variable(s), and w is the \
  357.     frequency-domain variable(s). \
  358.     Multidimensional inverse DTFT's are supported. \
  359.     Applying TheFunction to the InvDTFT operator will invoke the \
  360.     inverse DTFT rule base InvDTFTransform if loaded."
  361.  
  362. InvFT::usage =
  363.     "InvFT[w, t] is the inverse discrete Fourier transform operator. \
  364.     Here, t is the time-domain variable(s) and w is the \
  365.     frequency-domain variable(s). \
  366.     Multidimensional Fourier transforms are supported. \
  367.     Applying TheFunction to this operator will invoke the inverse \
  368.     continuous-time Fourier transform rule base InvCTFTransform if loaded."
  369.  
  370. InvL::usage =
  371.     "InvL[s, t] is the inverse Laplace transform operator. \
  372.     Applying TheFunction to the InvL operator will invoke the \
  373.     bilateral inverse Laplace rule base InvLaPlace if loaded."
  374.  
  375. InvZ::usage =
  376.     "InvZ[z, n] is the inverse z-transform operator. \
  377.     Applying TheFunction to the InvZ operator will invoke the inverse \
  378.     z-transform rule base InvZTransform if loaded."
  379.  
  380. L::usage =
  381.     "L[t, s] is the forward Laplace transform operator. \
  382.     Applying TheFunction to the L operator will invoke the bilateral \
  383.     Laplace rule base if loaded."
  384.  
  385. LineImpulse::usage =
  386.     "LineImpulse[nlist, coefflist] represents a line impulse where \
  387.     nlist is a list of variables like {n1,n2,n3} and coefflist is \
  388.     a corresponding list of coefficients like {1,2,3}. \
  389.     For the previous lists, the line impulse is a set of impulse \
  390.     along the line n1 = 2 n2 = 3 n3."
  391.  
  392. OperatorInOperExpr::usage =
  393.     "OperatorInOperExpr[ operator_expression ] returns the full \
  394.     operator in operator_expression. \
  395.     For example, Shift[2,n] would be returned from \
  396.     OperatorInOperExpr[ Shift[2,n][x[n]] ]."
  397.  
  398. OperatorName::usage =
  399.     "OperatorName[ operator_expression ] returns the head of the \
  400.     expression. \
  401.     For example, OperatorName[ Shift[2,n][x[n]] ] will return Shift."
  402.  
  403. ParametersInOperExpr::usage =
  404.     "ParametersInOperExpr[ operator_expression ] returns the parameters \
  405.     of the operator in operator_expression. \
  406.     For example, (2,n) would be returned from \
  407.     ParametersInOperExpr[ Shift[2,n][x[n]] ]."
  408.  
  409. Periodic::usage =
  410.     "Periodic[k,n][f] indicates that f is a function of n which is \
  411.     periodic with period of k."
  412.  
  413. PolyphaseDownsample::usage =
  414.     "PolyphaseDownsample[m, h, n][x] is equivalent to downsampling \
  415.     x by m (w/r to n) and then filtering (w/r to n) by a polyphase \
  416.     form of the FIR filter h. \
  417.     Hence, the filtering is carried out at the lower sampling rate."
  418.  
  419. PolyphaseUpsample::usage =
  420.     "PolyphaseUpsample[l, h, n][x] is equivalent to filtering (w/r to n) \
  421.     x by a polyphase form of the FIR filter h and then upsampling the \
  422.     result by l (w/r to n). \
  423.     Hence, the filtering is carried out at the lower sampling rate."
  424.  
  425. Pulse::usage =
  426.     "Pulse[len] and Pulse[len, n] define a pulse which begins at \
  427.     n = 0 and ends at n = len - 1. \
  428.     A discrete pulse centered at the origin is written as \
  429.     Pulse[len, n + (len - 1)/2] or Shift[-(len - 1)/2, n][Pulse[len, n]]. \
  430.     Sometime, a pulse will be automatically simplified; \
  431.     e.g., Pulse[0, n] is zero and Pulse[1, n] is really Impulse[n]."
  432.  
  433. RationalGCD::usage =
  434.     "RationalGCD[e1, e2, ...] returns the greatest common divisor of the \
  435.     numerators of elements ei divided by the greatest common divisor of \
  436.     the denominators of elements ei. \
  437.     Every element must be a polynomial or a number. \
  438.     Each real-valued and complex-valued element is rationalized \
  439.     before GCD's are computed."
  440.  
  441. Rev::usage =
  442.     "Rev[n][x] represents the operation of reversing the direction of x, \
  443.     with respect to the variables(s) n."
  444.  
  445. RewriteSummations::usage =
  446.     "RewriteSummations[f, t, tlower, tupper] rewrites Summation \
  447.     and Periodic operators that appear in f so that the domain \
  448.     of the new expression includes t in [tlower, tupper]. \
  449.     It relies on the Extent1D function to compute the domain \
  450.     of the arguments to the Periodic and Summation operators."
  451.  
  452. ScaleAxis::usage =
  453.     "ScaleAxis[l,w][x] represents the compression by a factor of l (an \
  454.     integer) of the continuous w axis of x, which is usually a \
  455.     continuous-frequency signal."
  456.  
  457. ScalingFactor::usage =
  458.     "ScalingFactor[expr, variable] returns the greatest common divisor \
  459.     of all coefficients of powers of z in expr. \
  460.     The powers of z that are functions of z are not considered. \
  461.     For example, ScalingFactor[ a z + a^2 z^2, z ] returns a. \
  462.     This function enables the implementation of the similarity \
  463.     property for transforms."
  464.  
  465. SequencePlot::usage =
  466.     "SequencePlot[f, {n, start, end}] plots real-valued 1-D sequences \
  467.     and has the same options as Show. \
  468.     You will have to apply Re or Im to f to plot the real or \
  469.     imaginary values of the sequence, respectively. \
  470.     SequencePlot[f, {n1, start1, end1}, {n2, start2, end2}] plots \
  471.     2-D sequences and supports the same options as Plot3D."
  472.  
  473. SequenceToFunction::usage =
  474.     "SequenceToFunction[seq], SequenceToFunction[seq, n], and \
  475.     SequenceToFunction[seq, n, noffset] return the sequence seq, \
  476.     {x[noffset], ..., x[noffset + N - 1]}, in symbolic form as a sum of \
  477.     impulse functions. \
  478.     For example, SequenceToFunction[{1, 2, 3}] -> \
  479.     Impulse[n] + 2 Impulse[n - 1] + 3 Impulse[n - 2]. \
  480.     For multidimensional sequences, the argument n must be a list of \
  481.     variables of appropriate length. \
  482.     For example, SequenceToFunction[{{1,2},{3,4}}, {n1, n2}] -> \
  483.     Impulse[n1,n2] + 2 Impulse[n1,n2-1] + 3 Impulse[n1-1,n2] + \
  484.     4 Impulse[n1-1, n2-2]."
  485.  
  486. Shift::usage =
  487.     "Shift[m,v][x] represents the shifting of the expression x by m \
  488.     samples to the right in the v direction, i.e. x[v] --> x[v - m]."
  489.  
  490. SignalCleanup::usage =
  491.     "SignalCleanup[ expr, t, nstart, nend ] converts the signal \
  492.     expression expr in variables t into a normal Mathematica expression \
  493.     that can be plotted over the interval [nstart, nend]. \
  494.     It returns a list of two expressions:  the first consists of the
  495.     Delta functions extracted from expr, and the second is the rest
  496.     of the expression."
  497.  
  498. SignalPlot::usage =
  499.     "SignalPlot[f, {t, start, end}] will plot f(t) as an one-dimensional, \
  500.     continuous-time function. \
  501.     It will show the real part as solid lines, \
  502.     and the imaginary part as dashed lines. \
  503.     Delta functions are plotted as upward pointing arrows. \
  504.     SignalPlot[f, {t1, start1, end1}, {t2, start2, end2}] treats f \
  505.     as a function of two variables t1 and t2. \
  506.     SignalPlot supports the same options as Plot for 1-D signals \
  507.     (functions) and Plot3D for 2-D signals (functions)."
  508.  
  509. SignalsInOperExpr::usage =
  510.     "SignalsInOperExpr[ operator_expression ] returns the signal(s) \
  511.     of the operator in operator_expression. \
  512.     For example, { x[n] } would be returned from \
  513.     SignalsInOperExpr[ Shift[2,n][x[n]] ]. \
  514.     Another version SignalsInOperExpr[ operator_expression, operator ] \
  515.     behaves as the first version if operator is the head of \
  516.     operator_expression; otherwise, operator_expression is returned."
  517.  
  518. Sinc::usage =
  519.     "Sinc[t] is the unit sinc function which is the ratio of \
  520.     Sin[t] over t.  Note that Sinc[0] = 1."
  521.  
  522. SPSimplify::usage =
  523.     "SPSimplify[e] will simplify expression e according to Mathematica's \
  524.     simplification rules and the rules in SPSimplificationRules. \
  525.     At each iteration, Simplify is called and SPSimplificationRules \
  526.     is applied to the result. \
  527.     Unlike Simplify, SPSimplify supports a Dialogue option. \
  528.     You can specify which symbols to treat as real variables by using \
  529.     the Variables option."
  530.  
  531. Step::usage =
  532.     "Step[n] is the unit step function which is 1 for n >= 0 \
  533.     and 0 otherwise. \
  534.     It is commonly used for discrete n. \
  535.     This function differs from CStep only at the origin."
  536.  
  537. Summation::usage =
  538.     "Summation[i][f], Summation[i, iend][f], and \
  539.     Summation[i, istart, iend, inc][f] represents the summation of f \
  540.     with respect to variable i:  i = (istart) to (iend) step (inc). \
  541.     The Summation operator is an abstraction of Mathematica's Sum object. \
  542.     Applying the object TheFunction to a Summation operator will invoke \
  543.     the Sum object if istart, iend, and inc are numbers."
  544.  
  545. TheFunction::usage =
  546.     "TheFunction[object] returns the mathematical function embedded \
  547.     in object. \
  548.     For list and transform objects, this function returns \
  549.     the first element after the head of the object; otherwise, the \
  550.     contents of the slot TheFunction are returned. \
  551.     For signal processing operations, \
  552.     the equivalent mathematical operation is returned."
  553.  
  554. ToContinuous::usage =
  555.     "ToContinuous[expr] replaces any discrete operator or signal \
  556.     in expr with its continuous equivalent."
  557.  
  558. ToDiscrete::usage =
  559.     "ToDiscrete[expr] replaces any continuous operator or signal \
  560.     in expr with its discrete equivalent."
  561.  
  562. Unit::usage =
  563.     "Unit[n][t] is the nth order continuous unit function in t. \
  564.     Unit[0][t] is the Dirac delta function (see Delta). \
  565.     Unit[-1][t] is the continuous step function (see CStep)."
  566.  
  567. Upsample::usage =
  568.     "Upsample[k,n][f] represents the upsampling operation on f, \
  569.     which is either an expression of n or a sequence (list) of values. \
  570.     Upsampling inserts k-1 zeroes between every two samples. \
  571.     In N dimensions, n is a list of N indices and k is an N x N matrix."
  572.  
  573. UpsampledFunction::usage =
  574.     "UpsampledFunction[m, fill, n, upf] represents the upsampling of f. \
  575.     In one-dimension, the upsampled form of f, upf, \
  576.     is obtained by evaluating n -> n / m."
  577.  
  578. UpsampleFactor::usage =
  579.     "UpsampleFactor[f, n] returns the upsampling index which can be \
  580.     a negative or positive number. \
  581.     If this routine returns 1 or -1, then no upsampling has occurred; \
  582.     if it returns 0, then f is constant with respect to n."
  583.  
  584. UpsampleSequence::usage =
  585.     "UpsampleSequence[seq,m,fill] inserts m-1 fill values between \
  586.     every two elements of seq."
  587.  
  588. Z::usage =
  589.     "Z[n, z] is the forward z-transform operator. \
  590.     Applying TheFunction to the Z operator will invoke the z-transform \
  591.     rule base ZTransform if loaded."
  592.  
  593. (*  E N D     U S A G E     I N F O R M A T I O N  *)
  594.  
  595.  
  596. Begin["`Private`"]
  597.  
  598.  
  599. (*  C O N S T A N T S  *)
  600.  
  601. axesdefaultvalue = If [ TrueQ[$VersionNumber >= 2.0], True, Automatic]
  602.  
  603. $DeltaFunctionScaling = Scaled
  604.  
  605.  
  606. (*  M E S S A G E S  *)
  607.  
  608. CircularShift::badlength =
  609.     "The sequence length parameter of the CircularShift \
  610.     operator must be non-zero."
  611.  
  612. DeltaPlot::unresolved = "These symbols were assigned a value of 1: ``."
  613.  
  614. Downsample::convert =
  615.     "Converting downsampling vector into a diagonal matrix: ``."
  616. Downsample::badmD =
  617.     "Downsampling factor has different dimensions than downsampled variables."
  618.  
  619. Pulse::notsym = "Last argument to Pulse is not a symbol."
  620.  
  621. Shift::badmD =
  622.     "Shift vector has different dimensions than the specified variables."
  623.  
  624. SequencePlot::nolist =
  625.     "It does not make sense to plot a list of 2-D sequences."
  626.  
  627. SignalPlot::nolist =
  628.     "It does not make sense to plot a list of 2-D functions."
  629.  
  630. Summation::extent =
  631.     "Could not compute which part of the summation should be plotted."
  632.  
  633. Upsample::convert =
  634.     "Converting upsampling vector into a diagonal matrix: ``."
  635. Upsample::badmD =
  636.     "Upsampling factor has different dimensions than upsampled variables."
  637.  
  638.  
  639.  
  640. (*  L O C A L     F U N C T I O N S  *)
  641.  
  642. (*  breakup  *)
  643. breakup[a_, z_] := a /; breakupQ[z][a]
  644. breakup[a_Times, z_] := Select[a, breakupQ[z]]
  645. breakup[x_, z_] := 1
  646.  
  647. breakupQ[z_][a_] := FreeQ[a, z]
  648.  
  649. (*  discBreakup  *)
  650. discBreakup[a_, z_] := a /; discBreakupQ[z][a]
  651. discBreakup[a_Times, z_] := Select[a, discBreakupQ[z]]
  652. discBreakup[x_, z_] := 1
  653.  
  654. discBreakupQ[z_][a_] := FreeQ[a, z] && Implies[ NumberQ[a], IntegerQ[a] ]
  655.  
  656. (*  gcdfilter --  rationalize floating point numbers        *)
  657. gcdfilter[x_Complex] := ToCollection[ gcdfilter[Re[x]], gcdfilter[Im[x]] ]
  658. gcdfilter[x_Real] := Rationalize[x]
  659. gcdfilter[x_] := x
  660.  
  661. (*  informatargs and informat  *)
  662. SetAttributes[informatargs, {Listable}]
  663. informatargs[m_, n_] := ToString[ StringForm["``  in  ``", m, n] ]
  664.  
  665. informat[op_, m_, n_] :=
  666. Format[ SequenceForm[op, Subscript[ ColumnForm[ToList[informatargs[m, n]]] ]] ]
  667.  
  668. (* intdivide --  kludge for Quotient primitive which has a problem  *)
  669. (*               under Mma 1.2 when the second argument is negative *)
  670. If [ TrueQ[ $VersionNumber >= 2.0 ],
  671.      intdivide[n_, m_] := Quotient[n, m],
  672.      intdivide[n_, m_] := Sign[m] Quotient[n, m Sign[m]] ]
  673.  
  674. (*  inTeXformat  *)
  675. inTeXformat[op_, m_, n_Symbol] := Subscripted[ op[m, n] ]
  676. inTeXformat[op_, m_, n_List] := Subscripted[ op[texFix[m], texFix[n]] ]
  677.  
  678. (*  mymax  *)
  679. mymax[x_, y_] := minmaxSimplify[ Max[Expand[x], Expand[y]] ]
  680.  
  681. (*  mymin  *)
  682. mymin[x_, y_] := minmaxSimplify[ Min[Expand[x], Expand[y]] ]
  683.  
  684. (*  minmaxSimplify  *)
  685. minmaxSimplify[x_] :=
  686.     x //. SignalProcessing`Support`SupCode`Private`MinMaxRules
  687.  
  688. (*  texFix  *)
  689. texFix[a_?VectorQ] := MatrixForm[ Transpose[{a}] ]
  690. texFix[a_] := delimitedMatrix[ a ]
  691.  
  692. (*  delimitedMatrix  *)
  693. delimitedMatrix/: Format[ delimitedMatrix[a_], TeXForm ] :=
  694.     StringForm["\\left[ `` \\right]", MatrixForm[a] ]
  695.  
  696.  
  697. (*  D E T E R M I N A T I O N     O F      V A R I A B L E S    *)
  698.  
  699. DummyVariables[i_, v_] :=
  700.     If [ i < 2,
  701.          v,
  702.          Table[GenerateSymbol[v, index], {index, 1, i}] ] /;
  703.     IntegerQ[i] && ( i >= 0 )
  704.  
  705. DummyVariables[i_, v_, context_] :=
  706.     If [ i < 2,
  707.          GenerateSymbol[v, " ", context],
  708.          Table[GenerateSymbol[v, index, context], {index, 1, i}] ] /;
  709.     IntegerQ[i] && ( i >= 0 )
  710.  
  711.  
  712. (*  F U N C T I O N S  *)
  713.  
  714. (*  Aliasby  *)
  715. Aliasby/: Aliasby[m_, w_][f_] := 1/m Periodic[2 Pi / m, w][ f ]
  716.  
  717. (*  old definitions  *)
  718. (*
  719. Aliasby/: Aliasby[1, w_][x_] := x
  720.  
  721. Aliasby/: Format[ Aliasby[m_, w_] ] := informat[ Aliasby, m, w ]
  722. Aliasby/: Format[ Aliasby[m_, w_], TeXForm ] := inTeXformat[ Aliasby, m, w ]
  723.  
  724. Aliasby/: GetOperatorVariables[ Aliasby[m_, w_] ] := w
  725.  *)
  726.  
  727. (*  CConvolve --  continuous convolution  *)
  728. CConvolve/: CConvolve[{t_Symbol}] := CConvolve[t]
  729. CConvolve/: CConvolve[t1_, trest__] := CConvolve[{t1, trest}]
  730.  
  731. CConvolve/: CConvolve[t_Symbol] [x_, c_. Delta[t_ + m_.]] :=
  732.     (c x) /. t -> (-m) /; FreeQ[m, t]
  733. CConvolve/: CConvolve[t_Symbol] [c_. Delta[t_ + m_.], x_] :=
  734.     (c x) /. t -> (-m) /; FreeQ[m, t]
  735.  
  736. CConvolve/: Extent1D[ CConvolve[t_][x__], t_ ] :=
  737.     Apply[ Plus, Map[ Extent1D[t], {x} ] ]
  738.  
  739. CConvolve/: CConvolve[tlist_List] [x_, c_. Delta[t_ + m_.]] :=
  740.     CConvolve[ Complement[tlist, {t}] ][x /. t -> (-m), c] /;
  741.     MemberQ[tlist, t] && FreeQ[m, t]
  742. CConvolve/: CConvolve[tlist_List] [c_. Delta[t_ + m_.], x_] :=
  743.     CConvolve[ Complement[tlist, {t}] ][c, x /. t -> (-m)] /;
  744.     MemberQ[tlist, t] && FreeQ[m, t]
  745.  
  746. CConvolve/: CConvolve[t_][x_, z_?ZeroQ] := z
  747. CConvolve/: CConvolve[t_][z_?ZeroQ, x_] := z
  748.  
  749. CConvolve/: Format[CConvolve[t_]] :=
  750.         Format[ Subscripted[CConvolve[t]] ]
  751. CConvolve/: Format[CConvolve[t_][x1_, x2_], TeXForm] :=
  752.         StringForm[ "`` \\star_{``} ``", Format[x1], t, Format[x2] ]
  753. CConvolve/: Format[CConvolve[t_][x1_, x2_, rest__], TeXForm] :=
  754.         Block [    {format, i, length, operstr, xlist},
  755.             xlist = {x1, x2, rest};
  756.             length = Length[xlist];
  757.             operstr = ToString[StringForm["\\star_{``}", t]];
  758.             str = StringJoin[" ", operstr, " ``"];
  759.             format = Apply[ StringJoin,
  760.                     Table[ str, {i, 1, length} ] ];
  761.             format = StringJoin["`` ", operstr, " ``", format];
  762.             Apply[StringForm, {format, Map[Format, xlist]}] ]
  763.  
  764. (*  CircularShift  *)
  765. CircularShift/: CircularShift[n0_, N_] := CircularShift[n0, N, Global`n]
  766.  
  767. CircularShift/: CircularShift[n0_, 0, n_][x_] :=
  768.     MyMessage[CircularShift::badlength, x]
  769.  
  770. CircularShift/: Extent1D[ CircularShift[n0_, N_, n_][f_], n_ ] := { 0, N-1 }
  771.  
  772. CircularShift/: TheFunction[ CircularShift[n0_Integer, N_Integer, n_][f_List] ] :=
  773.     RotateRight[ Take[f, N], n0 ]
  774.  
  775. CircularShift/: TheFunction[ CircularShift[n0_, N_, n_][f_] ] :=
  776.     TheFunction[f Pulse[N, n]] /. ( n -> Mod[n + n0, N] )
  777.  
  778. CircularShift/: N[ CircularShift[n0_, N_, n_][f_] ] :=
  779.     N[ TheFunction[CircularShift[n0, N, n][f]] /. ( n -> Mod[n + n0, N] ) ]
  780.  
  781. CircularShift/: Format[ CircularShift[n0_, N_, n_] ] :=
  782.     informat[CircularShift, Mod[n + n0, N], n]
  783. CircularShift/: Format[ CircularShift[m_,n_], TeXForm ] :=
  784.     inTeXformat[CircularShift, Mod[n + n0, N], n]
  785.  
  786. (*  CPulse  *)
  787. CPulse[l_] := CPulse[l, Global`t]            (* default args     *)
  788.  
  789. CPulse/: CPulse[l_, t_] := 1     /; N[0 < t < l]    (* definition        *)
  790. CPulse/: CPulse[l_, t_] := 0     /; N[(t < 0) || (t > l)]
  791. CPulse/: CPulse[l_, t_] := 1/2   /; N[(t == 0) || (t == l)]
  792. CPulse/: CPulse[Infinity, t_] := CStep[t]
  793. CPulse/: Extent1D[ CPulse[l_, a_. t_ + b_.], t_ ] :=
  794.         Extent1DOrder[-b/a, (l-b)/a] /;
  795.         FreeQ[{a,b,l}, t]
  796.  
  797. CPulse/: Format[ CPulse[l_, n_] ] :=            (* output forms     *)
  798.         Format[ CPulse Subscript[l] [n] ]
  799.  
  800. CPulse/: Format[ CPulse, TeXForm ] := "\\sqcap"    
  801. CPulse/: Format[ CPulse[l_, n_], TeXForm ] :=
  802.         StringForm[ "\\sqcap_{``} (``)", l, n ]
  803.  
  804. Derivative[0,1][CPulse] :=                (* derivative rule *)
  805.     ( Delta[#2] + Delta[#2 - #1] )&
  806.  
  807. Unprotect[Integrate]                    (* integration rules *)
  808. Integrate/: Integrate[f_. CPulse[L_, a_. x_ + b_.] + c_.,
  809.         vars1___, x_Symbol, vars2___] :=
  810.     1/a CPulse[a x + b] ( Integrate[f, vars1, x, vars2] /. x -> a x + b ) +
  811.       Integrate[c, vars1, x, vars2] /;
  812.     FreeQ[{a, b, L}, x]
  813. Integrate/: Integrate[expr_. CPulse[L_, a_. x_ + b_.] + c_.,
  814.             vars1___, {x_Symbol, x1_, x2_}, vars2___] :=
  815.     Sign[x2 - x1] *
  816.     cpulseintersect[ Min[x1, x2], Max[x1, x2],
  817.              Min[-b/a, (L - b)/a], Max[-b/a, (L - b)/a] ] *
  818.     Integrate[expr,
  819.           vars1,
  820.           {x, Max[Min[x1,x2], Min[-b/a, (L - b)/a]],
  821.               Min[Max[x1,x2], Max[-b/a, (L - b)/a]]},
  822.               vars2] +
  823.     Integrate[c, vars1, {x, x1, x2}, vars2] /;
  824.     FreeQ[{a, b, L}, x]
  825. Protect[Integrate]
  826.  
  827. cpulseintersect[x1_, x2_, x3_, x4_] := Step[x4 - x1] Step[x2 - x3]
  828.  
  829. (* CStep  *)
  830. CStep/: CStep[Infinity] := 1                (* definition         *)
  831. CStep/: CStep[t_] := 1        /; N[ t > 0 ]
  832. CStep/: CStep[t_] := 0        /; N[ t < 0 ]
  833. CStep/: CStep[0] := 1/2
  834. CStep/: CStep[0.] := 0.5
  835. CStep/: CStep[-Infinity] := 0
  836.  
  837. CStep/: Extent1D[ CStep[a_. t_ + b_.], t_ ] :=
  838.         Extent1DOrder[-b/a, Sign[a] Infinity] /;
  839.         FreeQ[{a,b}, t]
  840.  
  841. CStep/: CStep[t_, args__] := CStep[t] CStep[args]    (* multidimensional *)
  842. CStep/: CStep[List[args__]] := CStep[args]        (* separability     *)
  843.  
  844. CStep/: CStep[n_Symbol + m_.] CStep[n_Symbol  + k_.] :=    (* automatic        *)
  845.     CStep[n + Min[m,k]] /;                (* simplification   *)
  846.     NumberQ[m] && NumberQ[k]            (* rules        *)
  847. CStep/: CStep[n_Symbol + m_.] CStep[-n_Symbol + k_.] :=
  848.     CPulse[k + m, n + m] /;
  849.     N[ -m <= k ]
  850. CStep/: CStep[n_Symbol + m_.] CStep[-n_Symbol + k_.] := 0 /;
  851.     N[ -m > k ]
  852.  
  853. CStep/: Simplify[CStep[a_ n_Symbol + b_.]] :=        (* man. simp. rules *)
  854.     CStep[n + b/a] /;
  855.     MyFreeQ[{a,b}, n] && Implies[ NumberQ[N[a]], N[a > 0] ] 
  856. CStep/: Simplify[CStep[- a_ n_Symbol + b_.]] :=
  857.     CStep[-n + b/a] /;
  858.     MyFreeQ[{a,b}, n] && Implies[ NumberQ[N[a]], N[a > 0] ]
  859.  
  860. CStep/: Format[ CStep, TeXForm ] := "u_{-1}"        (* output form     *)
  861.  
  862. Derivative[1][CStep] := Delta                (* derivative rule *)
  863.  
  864. Unprotect[Integrate]                    (* integration rules *)
  865. Integrate/: Integrate[f_. CStep[a_. x_ + b_.] + c_.,
  866.         vars1___, x_Symbol, vars2___] :=
  867.     1/a CStep[a x + b] ( Integrate[f, vars1, x, vars2] /. x -> a x + b ) +
  868.       Integrate[c, vars1, x, vars2] /;
  869.     FreeQ[{a, b}, x]
  870. Integrate/: Integrate[expr_. CStep[a_. x_ + b_.] + c_.,
  871.             vars1___, {x_Symbol, x1_, x2_}, vars2___] :=
  872.     Sign[x2 - x1] *
  873.     cstepintersect[x1, x2, a, b] *
  874.     Integrate[expr,
  875.           vars1,
  876.           {x, csteplbound[x1, x2, a, b], cstepubound[x1, x2, a, b]},
  877.               vars2] +
  878.     Integrate[c, vars1, {x, x1, x2}, vars2] /;
  879.     FreeQ[{a, b}, x]
  880. Protect[Integrate]
  881.  
  882. cstepintersect[x1_, x2_, a_, b_] :=
  883.     If [ Positive[a],
  884.          Step[Max[x1, x2] + b/a],
  885.              Step[-b/a - Min[x1,x2]] ]
  886.  
  887. csteplbound[x1_, x2_, a_, b_] :=
  888.     minmaxSimplify[Max[Min[x1, x2], -b/a]] /; Positive[a]
  889. csteplbound[x1_, x2_, a_, b_] :=
  890.     minmaxSimplify[Min[x1, x2]] /; Negative[a]
  891. cstepubound[x1_, x2_, a_, b_] :=
  892.     minmaxSimplify[Max[x1, x2]] /; Positive[a]
  893. cstepubound[x1_, x2_, a_, b_] :=
  894.     minmaxSimplify[Min[Max[x1, x2], -b/a]] /; Negative[a]
  895.  
  896. Format[csteplbound[x1_, x2_, a_, b_]] :=
  897.     SequenceForm["LeftEndpointOf[", {x1,x2}, " and step at ", -b/a, "]"]
  898. Format[cstepubound[x1_, x2_, a_, b_]] :=
  899.     SequenceForm["RightEndpointOf[", {x1,x2}, " and step at ", -b/a, "]"]
  900.  
  901. (*  Convolve --  discrete convolution  *)
  902. Convolve/: Convolve[{n_Symbol}] := Convolve[n]
  903. Convolve/: Convolve[n1_, nrest__] := Convolve[{n1, nrest}]
  904.  
  905. Convolve/: Convolve[n_] [x_, c_. Impulse[n_ + m_.]] :=
  906.     (c x) /. n -> (-m) /; FreeQ[m, t]
  907. Convolve/: Convolve[n_] [c_. Impulse[n_ + m_.], x_] :=
  908.     (c x) /. n -> (-m) /; FreeQ[m, t]
  909.  
  910. Convolve/: Extent1D[ Convolve[n_][x__], n_ ] :=
  911.     Apply[ Plus, Map[ Extent1D[n], {x} ] ]
  912.  
  913. Convolve/: Convolve[nlist_List] [x_, c_. Impulse[n_ + m_.]] :=
  914.     Convolve[ Complement[nlist, {n}] ][x /. n -> (-m), c] /;
  915.     MemberQ[nlist, n] && FreeQ[m, n]
  916. Convolve/: Convolve[nlist_List] [c_. Impulse[n_ + m_.], x_] :=
  917.     Convolve[ Complement[nlist, {n}] ][c, x /. n -> (-m)] /;
  918.     MemberQ[nlist, n] && FreeQ[m, n]
  919.  
  920. Convolve/: Convolve[n_][x_, z_?ZeroQ] := z
  921. Convolve/: Convolve[n_][z_?ZeroQ, x_] := z
  922.  
  923.     (*  Formatting the convolution operator *)
  924.  
  925. Convolve/: Format[Convolve[n_]] :=
  926.         Format[ Subscripted[Convolve[n]] ]
  927. Convolve/: Format[Convolve[n_][x1_, x2_], TeXForm] :=
  928.         StringForm[ "`` \\star_{``} ``", Format[x1], n, Format[x2] ]
  929. Convolve/: Format[Convolve[n_][x1_, x2_, rest__], TeXForm] :=
  930.         Block [    {format, i, length, operstr, xlist},
  931.             xlist = {x1, x2, rest};
  932.             length = Length[xlist];
  933.             operstr = ToString[StringForm["\\star_{``}", n]];
  934.             str = StringJoin[" ", operstr, " ``"];
  935.             format = Apply[ StringJoin,
  936.                     Table[ str, {i, 1, length} ] ];
  937.             format = StringJoin["`` ", operstr, " ``", format];
  938.             Apply[StringForm, {format, Map[Format, xlist]}] ]
  939.  
  940. (*  Delta  *)
  941. Delta/: Delta[Infinity] := 0                (* definition         *)
  942. Delta/: Delta[t_] := 0        /; N[ t != 0 ]
  943. Delta/: Delta[-Infinity] := 0
  944.  
  945. Delta/: Delta[a_. x_Symbol + b_.] Delta[c_. x_ + d_.] := 0 /; ( b c != a d )
  946. Delta/: Delta[a_. x_Symbol + b_.] Delta[a_. x_ + d_.] := 0 /; ( b != d )
  947.  
  948. Delta/: Extent1D[ Delta[a_. t_ + b_.], t_ ] := { -b/a, -b/a } /;
  949.     FreeQ[{a,b}, t]
  950.  
  951. Delta/: Delta[t_, args__] := Delta[t] Delta[args]    (* multidimensional  *)
  952. Delta/: Delta[List[args__]] := Delta[args]        (* separability         *)
  953.  
  954. Delta/: Format[ Delta, TeXForm ] := "\\delta"        (* output form       *)
  955.  
  956. Derivative[1][Delta] := Unit[1]                (* derivative rule   *)
  957.  
  958.     (* The following Delta rules were written by John Mitchell *)
  959.     (* and modified by Brian Evans.                   *)
  960. getivars[ x_Symbol ] := x
  961. getivars[ {x_Symbol, xl_, xu_} ] := x
  962. Unprotect[Integrate]                    (* integration rules *)
  963. Integrate/: Integrate[a_. + expr_. Delta[term_], vars_] :=
  964.     Integrate[a, vars] + DeltaIntegrate[expr Delta[term], vars] /;
  965.     ! FreeQ[ term, getivars[vars] ]
  966. Integrate/: Integrate[a_. + expr_. Delta[term_], vars1___, vars_, vars2___] :=
  967.     Integrate[a, vars1, vars, vars2] + 
  968.       Integrate[ DeltaIntegrate[expr Delta[term], vars], vars1, vars2 ] /;
  969.     ! FreeQ[ term, getivars[vars] ]
  970. Protect[Integrate]
  971.  
  972. (*  DeltaIntegrate  *)
  973. DeltaIntegrate[expr_. Delta[a_. x_ + b_.], x_Symbol] :=
  974.     Limit[expr, x -> -b/a] CStep[x + b/a] / Abs[a] /;
  975.     FreeQ[{a,b}, x] && FreeQ[expr, Delta]
  976. DeltaIntegrate[expr_. Delta[a_. x_ + b_.], {x_Symbol, x1_, x1_}] := 0
  977. DeltaIntegrate[expr_. Delta[a_ x_ + b_.], {x_Symbol, x1_, x2_}] :=
  978.     If [ N[x1 > x2],
  979.          -1 DeltaIntegrate[expr Delta[a x + b], {x, x2, x1}],
  980.          Integrate[expr Delta[x + b/a] / Abs[a], {x, x1, x2}],
  981.          Integrate[expr Delta[x + b/a] / Abs[a], {x, x1, x2}] ] /;
  982.     FreeQ[{a,b}, x] && FreeQ[expr, Delta]
  983. DeltaIntegrate[expr_. Delta[x_ + c_.], {x_Symbol, x1_, x2_}] :=
  984.     If [ N[x1 > x2],
  985.          -1 DeltaIntegrate[expr Delta[x + c], {x, x2, x1}],
  986.          Limit[expr, x -> -c] CStep[-c - x1] CStep[c + x2],
  987.          Limit[expr, x -> -c] CStep[-c - x1] CStep[c + x2] ] /;
  988.     FreeQ[c, x] && FreeQ[expr, Delta]
  989.         (* CStep[-c - x1] CStep[c + x2] <--> x1 <= -c <= x2 *)
  990. DeltaIntegrate[Delta[a_. x_ + b_.] Delta[c_.x_ + d_.],
  991.               {x_Symbol, x1_, x2_}] :=
  992.     If [ N[x1 > x2],
  993.          -1 DeltaIntegrate[Delta[a x + b] Delta[c x + d], {x, x2, x1}],
  994.          (1/Abs[a c]) Delta[-b/a + d/c] *
  995.         CStep[-(b/a) - x1] CStep[(b/a) + x2],
  996.          (1/Abs[a c]) Delta[-b/a + d/c] *
  997.         CStep[-(b/a) - x1] CStep[(b/a) + x2] ] /;
  998.     FreeQ[{a,b,c,d}, x]
  999. DeltaIntegrate[Delta[a_. x_ + b_.]^2, {x_Symbol, x1_, x2_}] :=
  1000.     If [ N[x1 > x2],
  1001.          -1 DeltaIntegrate[Delta[a x + b]^2, {x, x2, x1}],
  1002.          (1/a^2) Delta[0] CStep[-(b/a) - x1] CStep[(b/a) + x2],
  1003.          (1/a^2) Delta[0] CStep[-(b/a) - x1] CStep[(b/a) + x2] ] /;
  1004.     FreeQ[{a,b}, x]
  1005.  
  1006. (*  DeltaPlot--  plot Delta functions as special case of continuous plotting  *)
  1007.  
  1008. rewriteSymbolicSummation[index_, istart_, iend_, inc_,
  1009.              c_, b_, a_, {t_, tmin_, tmax_} ] :=
  1010.         Block [ {aa = a, adjfun, bb = b, cc = c, defaults, f1, f2,
  1011.            i, indexfunoft, minindex, maxindex, rules, varlist},
  1012.           varlist = Select[GetVariables[{a, b, c}],
  1013.                       ((! SameQ[#1, t]) &&
  1014.                     (! SameQ[#1, index]))&];
  1015.           If [ ! EmptyQ[varlist],
  1016.                defaults = Map[(#1 -> 1)&, varlist];
  1017.                aa = a /. defaults;
  1018.                bb = b /. defaults;
  1019.                cc = c /. defaults ];
  1020.           rules = Solve[ bb t + aa == 0, index ];
  1021.           indexfunoft = Replace[index, First[rules] ];
  1022.           f1 = N[ indexfunoft /. t -> tmin ];
  1023.           f2 = N[ indexfunoft /. t -> tmax ];
  1024.           minindex = Max[ istart, Ceiling[Min[f1, f2]] ];
  1025.           maxindex = Min[ iend, Max[f1, f2] ];
  1026.           adjfun = ((cc /. t -> - aa / bb) Delta[bb t + aa]) /.
  1027.                index -> i;
  1028.           Apply[ Plus,
  1029.              Table[adjfun, {i, minindex, maxindex, inc}] ] ]
  1030.  
  1031. dpcleanup[deltafuns_, t_, tmin_, tmax_] :=
  1032.     Block [    {delfuns, itemp, varlist = {}},
  1033.         delfuns = deltafuns /.
  1034.                 ( d_ Summation[index_, istart_, iend_, inc_][c_] :>
  1035.                   Summation[index, istart, iend, inc][c d] );
  1036.         delfuns = delfuns /.
  1037.         { Summation[index_, istart_, iend_, inc_]
  1038.                [c_. Delta[b_. t + a_.]] :>
  1039.             rewriteSymbolicSummation[ index, istart, iend, inc, c,
  1040.                           b, a, {t, tmin, tmax} ],
  1041.           Periodic[k_, t][c_. Delta[b_. t + a_.]] :>
  1042.             rewriteSymbolicSummation[ itemp, -Infinity, Infinity, 1,
  1043.                           c, b, a + itemp k b,
  1044.                           {t, tmin, tmax} ] };
  1045.         varlist = Sort[ varlist ~Join~
  1046.                 Select[ GetVariables[delfuns],
  1047.                     (! SameQ[#1, t])& ] ];
  1048.         If [ ! EmptyQ[varlist],
  1049.              Message[ DeltaPlot::unresolved, varlist ];
  1050.              delfuns = delfuns /. Map[(#1 -> 1)&, varlist] ];
  1051.  
  1052.         delfuns ]
  1053.  
  1054. getheight[ c_. Delta[a_. t_ + b_.], t_ ] := N[ c / Abs[a] ]
  1055.  
  1056. getlocation[ c_. Delta[a_. t_ + b_.], t_ ] := N[ - b / a ]
  1057.  
  1058. DeltaPlot[deltafuns_, t_, start_, end_] :=
  1059.     DeltaPlot[deltafuns, t, start, end, 0, 1]
  1060.  
  1061. DeltaPlot[deltafuns_, t_, start_, end_, plot_] := plot /;
  1062.     FreeQ[deltafuns, t]
  1063.  
  1064.     (* Use PlotRange as function to find range of plot [see MJ v1 #4 p47] *)
  1065. DeltaPlot[deltafuns_, t_, start_, end_, plot_] :=
  1066.     Block [    {xmax, xmin, ylist, ymax, ymin},
  1067.         {{xmin, xmax}, {ymin, ymax}} = PlotRange[plot];
  1068.         DeltaPlot[deltafuns, t, start, end, plot, ymin, ymax] ]
  1069.  
  1070. DeltaPlot[deltafuns_, t_, start_, end_, min_, max_] := NullPlot /;
  1071.     FreeQ[deltafuns, t]
  1072.  
  1073.     (* every version of DeltaPlot calls this one *)
  1074. DeltaPlot[deltafuns_, t_, start_, end_, min_, max_] :=
  1075.     Block [    {bottom, delfuns, height, heightList, length,
  1076.          locations, nend, nstart, width},
  1077.         nstart = N[start];
  1078.         nend = N[end];
  1079.         delfuns = Expand[ dpcleanup[deltafuns, t, nstart, nend] ];
  1080.         delfuns = If [ SameQ[Head[delfuns], Plus],
  1081.                    Apply[List, delfuns],
  1082.                    { delfuns } ];
  1083.         delfuns = Select[ delfuns,
  1084.                   N[LessEqual[nstart, getlocation[#, t], nend]]& ];
  1085.         height = N[max - min];
  1086.         width = nend - nstart;
  1087.         locations = Map[ getlocation[#1, t]&, delfuns];
  1088.         If [ min <= 0,
  1089.              bottom = 0; length = max,
  1090.              bottom = min; length = height ];
  1091.         length = Min[height, max];
  1092.         Which [ SameQ[locations, {}],
  1093.                   NullPlot,
  1094.             SameQ[$DeltaFunctionScaling, None],
  1095.                   Map[Arrow2D[{#1, bottom}, width, height, length]&,
  1096.                   locations ],
  1097.             True,
  1098.               heightList = Map[ getheight[#1, t]&, delfuns ];
  1099.               Map[ Arrow2D[{#[[1]],bottom}, width, height, #[[2]]]&,
  1100.                    Transpose[ {locations, heightList} ] ] ] ]
  1101.  
  1102. DeltaPlot[deltafuns_, t_, start_, end_, plot_, min_, max_] :=
  1103.     Block [    {deltaplot, ymax = max, ymin = min},
  1104.         If [ ymax == ymin,
  1105.              Which [ ymin > 0,  ymin = -ymax,
  1106.                  ymin == 0, ymax = 1,
  1107.                  ymin < 0,  ymax = -ymin ] ];
  1108.         deltaplot = DeltaPlot[deltafuns, t, start, end, ymin, ymax];
  1109.         If [ SameQ[deltaplot, NullPlot],
  1110.              plot,
  1111.              Prepend[ deltaplot, plot ] ] ]
  1112.  
  1113. (*  Difference  *)
  1114. Difference/: TheFunction[Difference[k_, n_][f_]] :=
  1115.     Block [    {jj, newf},
  1116.         newf = TheFunction[f] /. n ~ReplaceWith~ (n - jj);
  1117.         Apply[ Plus,
  1118.                Table[(-1)^jj Binomial[k,jj] newf, {jj, 0, k}] ] ] /;
  1119.     IntegerQ[k] && k > 0
  1120.  
  1121. Difference/: Extent1D[ Difference[k_, n_][f_], n_ ] := Extent1D[f, n]
  1122.  
  1123. Difference/: N[Difference[1, n_][f_]] := f - ( f /. n ~ReplaceWith~ (n - 1) )
  1124. Difference/: N[Difference[k_,n_][f_]] :=
  1125.     Apply[Plus,
  1126.           Table[(-1)^jj Binomial[k,jj] f /. n ~ReplaceWith~ (n - jj),
  1127.             {jj, 0, k}] ] /;
  1128.     IntegerQ[k] && k > 0
  1129.  
  1130. Difference/: Format[ Difference[k_, n_] ] := informat[Difference, k, n]
  1131.  
  1132. Difference/: Format[ Difference, TeXForm ] := "\\Delta"
  1133. Difference/: Format[ Difference[k_,n_], TeXForm ] :=
  1134.         inTeXformat[ Difference, k, n ]
  1135.  
  1136. Difference/: GetOperatorVariables[ Difference[k_, n_] ] := n
  1137.  
  1138. (*  Dirichlet  *)
  1139. Dirichlet/: Dirichlet[len_, 0] := len            (* definition    *)
  1140. Dirichlet/: Dirichlet[len_, k_?EvenQ Pi] := len (-1)^(len - 1)
  1141. Dirichlet/: Dirichlet[len_Integer, w_?NumberQ] :=
  1142.         Sin[len w / 2] / ( len Sin[w / 2] )
  1143.  
  1144. Dirichlet/: TheFunction[Dirichlet[len_, w_]] :=
  1145.         Sin[len w / 2] / ( len Sin[w / 2] )
  1146.  
  1147. Dirichlet/: N[ Dirichlet[len_, w_] ] := N [ TheFunction[Dirichlet[len, w]] ]
  1148.  
  1149. Dirichlet/: Format[ Dirichlet[l_, n_] ] :=        (* output forms     *)
  1150.         Format[ Dirichlet Subscript[l] [n] ]
  1151.  
  1152. (*  DiscreteGraphics  *)
  1153. oneline[xycoord_] :=
  1154.     ToCollection[ Line[{{xycoord[[1]], 0}, xycoord}], Point[xycoord] ]
  1155. DiscreteGraphics[coordlist_List, lthick_:0.008, pthick_:0.024 ] :=
  1156.     Graphics[ Join[ { Thickness[lthick], PointSize[pthick] },
  1157.             N [ Map[oneline, coordlist] ] ] ]
  1158.  
  1159. (*  Downsample [Myers, 219] [Bamberger, ch. 2]  *)
  1160.  
  1161.     (* Error checking of downsample parameters  *)
  1162.  
  1163. Downsample/: Downsample[m_List, n_List][f_] :=
  1164.     MyMessage[ Downsample::convert,
  1165.            Downsample[DiagonalMatrix[m], n][f],
  1166.            m ] /;
  1167.     VectorQ[m] && SameQ[Length[m], Length[n]] && ! PatternQ
  1168.  
  1169. Downsample/: Downsample[m_List, n_List][f_] :=
  1170.     MyMessage[Downsample::badmD, f] /;
  1171.     VectorQ[m] && ! SameQ[Length[m], Length[n]]
  1172.  
  1173. Downsample/: Downsample[m_List, n_List][f_] :=
  1174.     MyMessage[Downsample::badmD, f] /;
  1175.     MatrixQ[m] && ! Apply[SameQ, Append[Dimensions[m], Length[n]]]
  1176.  
  1177. Downsample/: Downsample[m_List, n_Symbol][f_] :=
  1178.     MyMessage[Downsample::badmD, f]
  1179.  
  1180.         (*  degenerate cases  *)
  1181.  
  1182. Downsample/: Downsample[1, n_Symbol][c_] := c
  1183. Downsample/: Downsample[-1, n_Symbol][c_] := Rev[n][c]
  1184.  
  1185.     (* convert upsample into a functional form  *)
  1186.  
  1187. Downsample/: TheFunction[Downsample[m_, n_Symbol][f_]] :=
  1188.     TheFunction[f] /. ( n -> m n )
  1189. Downsample/: TheFunction[Downsample[m_, n_List][f_]] :=
  1190.     TheFunction[f] /. ( n ~ReplaceWith~ (m . n) ) /;
  1191.     MatrixQ[m] && VectorQ[n]
  1192.  
  1193. Downsample/: N [ Downsample[m_, n_][f_] ] :=
  1194.     N [ TheFunction[Downsample[m,n][f]] ]
  1195.  
  1196.     (*  extent of downsample operation  *)
  1197.  
  1198. Downsample/: Extent1D[ Downsample[m_, n_][f_], n_ ] :=
  1199.     intdivide[ Extent1D[f, n], m ]
  1200.  
  1201.     (* formatting of the downsample operator *)
  1202.  
  1203. Downsample/: Format[ Downsample[m_, n_List] ] :=
  1204.     Block [    {bar},
  1205.         bar = TableForm[ Apply[ Table,
  1206.                     { "  |  ", Dimensions[n] } ] ];
  1207.         Format[ SequenceForm[ Downsample,
  1208.                       Subscript[ TableForm[m] ],
  1209.                       Subscript[ bar ],
  1210.                       Subscript[ TableForm[n] ] ] ] ]
  1211. Downsample/: Format[ Downsample[m_, n_] ] :=
  1212.     Format[ Subscripted[Downsample[m,n]] ]
  1213.  
  1214. Downsample/: Format[ Downsample, TeXForm ] := "\\downarrow"
  1215. Downsample/: Format[ Downsample[m_, n_], TeXForm ] :=
  1216.     inTeXformat[ Downsample, m, n ]
  1217.  
  1218. Downsample/: GetOperatorVariables[ Downsample[m_, n_] ] := n
  1219.  
  1220. (*  DFT  [Myers, 221]  *)
  1221. DFT/: DFT[L_, n_] := DFT[L, n, DummyVariables[Length[n], Global`k]]
  1222. DFT/: DFT[L_, n_, k_] [ InvDFT[L_, ki_, n_] [f_] ] := 
  1223.     If [ SameQ[k, ki], f, f /. ReplaceWith[ki, k] ] /;
  1224.     Length[k] == Length[ki]
  1225.  
  1226. DFT/: DFT^-1[a__] := InvDFT[a]
  1227.  
  1228. DFT/: Format[ DFT, TeXForm ] := "{\\cal DFT}"
  1229. DFT/: Format[ DFT[L_, n_, k_], TeXForm ] :=
  1230.     StringForm[ "{\\cal DFT}_{``, L = ``}", n, L]
  1231.  
  1232. DFT/: GetOperatorVariables[ DFT[L_, n_, k_] ] := n
  1233.  
  1234. DFT/: Extent1D[ DFT[L_, n_, k_][f_], n_ ] := {0, L}
  1235. DFT/: Extent1D[ DFT[L_, n_, k_][f_], k_ ] := {0, L}
  1236.  
  1237. (*  DTFT  *)
  1238. DTFT/: DTFT[n_] := DTFT[n, DummyVariables[Length[n], Global`w]]
  1239. DTFT/: DTFT[n_, w_] [ InvDTFT[wi_, n_] [f_] ] :=
  1240.     If [ SameQ[w, wi], f, f /. ReplaceWith[wi, w] ] /;
  1241.     Length[w] == Length[wi]
  1242.  
  1243. DTFT/: DTFT^-1[a__] := InvDTFT[a]
  1244.  
  1245. DTFT/: Format[ DTFT, TeXForm ] := "{\\cal DTFT}"
  1246. DTFT/: Format[ DTFT[n_, w_], TeXForm ] := StringForm[ "{\\cal DTFT}_{``}", n ]
  1247.  
  1248. (*  Extent1D  *)
  1249. lastExpression = Null
  1250.  
  1251. modifiedQ[x_, n_] :=
  1252.     Block [    {},
  1253.         lastExpression = x /.
  1254.           ( f_ :> Collect[f, n] /;
  1255.             PolynomialQ[f, n] || MixedPolynomialQ[Expand[f], n] );
  1256.         ! SameQ[ x, lastExpression ] ]
  1257.  
  1258. Extent1DUnion[ {x1_, y1_}, {x2_, y2_} ] :=
  1259.     { mymin[x1, x2], mymax[y1, y2] }
  1260. Extent1DIntersection[ {x1_, y1_}, {x2_, y2_} ] :=
  1261.     { mymax[x1, x2], mymin[y1, y2] }
  1262. Extent1DOrder[ x1_, y1_ ] :=
  1263.     { mymin[x1, y1], mymax[x1, y1] }
  1264.  
  1265. Extent1D[t_][x_] := Extent1D[x, t]
  1266.  
  1267. Extent1D[x_ + y_, n_] := Extent1DUnion[ Extent1D[x, n], Extent1D[y, n] ]
  1268. Extent1D[x_ y_, n_] := Extent1DIntersection[ Extent1D[x, n], Extent1D[y, n] ]
  1269. Extent1D[0, n_] := {0, 0}
  1270. Extent1D[x_, n_] := Extent1D[lastExpression, n] /; modifiedQ[x, n]
  1271. Extent1D[x_, n_] := {-Infinity, Infinity}
  1272.  
  1273. (*  FT  *)
  1274. FT/: FT[n_] := FT[n, DummyVariables[Length[n], Global`w]]
  1275. FT/: FT[n_, w_] [ InvFT[wi_, n_] [f_] ] :=
  1276.     If [ SameQ[w, wi], f, f /. ReplaceWith[wi, w] ] /;
  1277.     Length[w] == Length[wi]
  1278.  
  1279. FT/: FT^-1[a__] := InvFT[a]
  1280.  
  1281. FT/: Format[ FT, TeXForm ] := "{\\cal F}"
  1282. FT/: Format[ FT[n_, w_], TeXForm ] := StringForm[ "{\\cal F}_{``}", n ]
  1283.  
  1284. (*  GetDeltaFunctions  *)
  1285. choose[{a_, aterm_}] := If [ SameQ[aterm, 0], a, aterm ]
  1286.  
  1287.     (* rules specific for 1-D functions of t  *)
  1288. GetDeltaFunctions[ c_. Delta[a_. t_Symbol + b_.], t_Symbol ] :=
  1289.     c Delta[a t + b]
  1290.  
  1291.     (* rules specific for m-D functions of t1, t2, ...  *)
  1292. GetDeltaFunctions[ c_. Delta[a_. t_Symbol + b_.], tlist_List ] :=
  1293.     c Delta[a t + b] /;
  1294.     MemberQ[tlist, t]
  1295.  
  1296.     (* rules for all dimensions  *)
  1297. GetDeltaFunctions[ a_ + b_, rest__ ] :=
  1298.     GetDeltaFunctions[a, rest] + GetDeltaFunctions[b, rest]
  1299. GetDeltaFunctions[ h_[b__], rest__ ] :=
  1300.     Block [ {arglist, deltalist},
  1301.         arglist = {b};
  1302.         deltalist = Map[ GetDeltaFunctions[#1, rest]&, arglist ];
  1303.         If [ SameQ[Apply[Plus, deltalist], 0],
  1304.              0,
  1305.              Apply[h, Map[choose, Transpose[{arglist, deltalist}]]] ] ]
  1306. GetDeltaFunctions[ x_, rest__ ] := 0
  1307.  
  1308.  
  1309. (*  Impulse  *)
  1310. Impulse/: Impulse[Infinity] := 0               (* definition       *)
  1311. Impulse/: Impulse[n_] := 0    /; N[ n != 0 ]
  1312. Impulse/: Impulse[n_] := 1    /; N[ n == 0 ]
  1313. Impulse/: Impulse[-Infinity] := 0
  1314.  
  1315. Impulse/: Extent1D[ Impulse[a_. n_ + b_.], n_ ] := { -b/a, -b/a } /;
  1316.     FreeQ[{a,b}, n]
  1317.  
  1318. Impulse/: Impulse[n_, args__] := Impulse[n] Impulse[args] (* multidimensional *)
  1319. Impulse/: Impulse[List[args__]] := Impulse[args]      (* separability     *)
  1320.  
  1321. Impulse/: Format[ Impulse[n_], TeXForm ] :=          (* output form rule *)
  1322.       StringForm["\\delta[``]", n]
  1323.  
  1324. (*  Interleave [Myers, 219-220]  *)
  1325. Interleave/: Interleave[n_][x_] := x               (* definition          *)
  1326. Interleave/: TheFunction[Interleave[n_][x1_, x__]] :=
  1327.     Block [    {index = Unique["k"], L, xlist},
  1328.         xlist = List[x1, x];
  1329.         L = Length[xlist];
  1330.         Summation[index, 0, L-1, 1]
  1331.              [ Shift[index, n] [Upsample[L, n]
  1332.                          [ Element[xlist, index + 1] ] ] ] ]
  1333. Interleave/: N [ Interleave[n_][x1_, x__] ] :=
  1334.     N [ TheFunction[Interleave[n][x1,x]] ]
  1335.  
  1336. Interleave/: Format[ Interleave[n_] ] :=        (* output form rules *)
  1337.         Format[ Subscripted[Interleave[n]] ]
  1338. Interleave/: Format[ Interleave[n_], TeXForm ] :=
  1339.         Format[ Subscripted[Interleave[n]] ]
  1340.  
  1341.  
  1342. (*  IntervalsToFunction  *)
  1343. IntervalsToFunction[interlist_, n_:Global`n, step_:Step, pulse_:Pulse] :=
  1344.     Block [    {int, len, signal},
  1345.  
  1346.         MakeOne[interval_] :=
  1347.           Block [
  1348.             {f, nminus, nplus, pulselen},
  1349.             f = interval[[1]];
  1350.             nminus = interval[[2]];
  1351.             nplus = interval[[3]];
  1352.             pulselen = nplus - nminus + 1;
  1353.             Which [ SameQ[nminus, -Infinity],
  1354.                   f step[nplus - n],
  1355.                 SameQ[nplus, Infinity],
  1356.                   f step[n - nminus],
  1357.                 True,
  1358.                   f pulse[pulselen, n - nminus] ] ];
  1359.  
  1360.         len = Length[interlist];
  1361.         signal = MakeOne[ interlist[[1]] ];
  1362.         For [ int = 2, int <= len, int++,
  1363.               signal += MakeOne[ interlist[[int]] ] ];
  1364.  
  1365.         signal ]
  1366.  
  1367. (*  InvDFT  [Myers, 221]  *)
  1368. InvDFT/: InvDFT[L_, k_] :=
  1369.     InvDFT[L, k, DummyVariables[Length[k], Global`n]]
  1370. InvDFT/: InvDFT[L_, k_, ni_] [ DFT[L_, n_, k_] [f_] ] :=
  1371.     If [ SameQ[ni, n], f, f /. ReplaceWith[n, ni] ] /;
  1372.     Length[ni] == Length[n]
  1373.  
  1374. InvDFT/: Format[ InvDFT, TeXForm ] := "{\\cal DFT}^{-1}"
  1375. InvDFT/: Format[ InvDFT[L_, k_, n_], TeXForm ] :=
  1376.       StringForm[ "{\\cal DFT}^{-1}_{``, L = ``}", k, L ]
  1377.  
  1378. InvDFT/: GetOperatorVariables[ InvDFT[L_, k_, n_] ] := k
  1379.  
  1380. InvDFT/: Extent1D[ InvDFT[L_, k_, n_][f_], n_ ] := {0, L}
  1381. InvDFT/: Extent1D[ InvDFT[L_, k_, n_][f_], k_ ] := {0, L}
  1382.  
  1383. (*  InvDTFT  *)
  1384. InvDTFT/: InvDTFT[w_] := InvDTFT[w, DummyVariables[Length[w], Global`n]]
  1385. InvDTFT/: InvDTFT[w_, ni_] [ DTFT[n_, w_] [f_] ] :=
  1386.     If [ SameQ[ni, n], f, f /. ReplaceWith[n, ni] ] /;
  1387.     Length[ni] == Length[n]
  1388.  
  1389. InvDTFT/: Format[ InvDTFT, TeXForm ] := "{\\cal DTFT}^{-1}"
  1390. InvDTFT/: Format[ InvDTFT[w_, n_], TeXForm ] :=
  1391.       StringForm[ "{\\cal DTFT}^{-1}_{``}", w ]
  1392.  
  1393. (*  InvFT  *)
  1394. InvFT/: InvFT[w_] := InvFT[w, DummyVariables[Length[w], Global`t]]
  1395. InvFT/: InvFT[w_, ti_] [ FT[t_, w_] [f_] ] :=
  1396.     If [ SameQ[ti, t], f, f /. ReplaceWith[t, ti] ] /;
  1397.     Length[ti] == Length[t]
  1398.  
  1399. InvFT/: Format[ InvFT, TeXForm ] := "{\\cal F}^{-1}"
  1400. InvFT/: Format[ InvFT[w_, t_], TeXForm ] :=
  1401.       StringForm[ "{\\cal F}^{-1}_{``}", w ]
  1402.  
  1403. (*  InvL  *)
  1404. InvL/: InvL[s_] := InvL[s, DummyVariables[Length[s], Global`t]]
  1405. InvL/: InvL[s_, ti_] [ L[t_, s_] [f_] ] :=
  1406.     If [ SameQ[ti, t], f, f /. ReplaceWith[t, ti] ] /;
  1407.     Length[t] == Length[ti]
  1408.  
  1409. InvL/: Format[ InvL, TeXForm ] := "{\\cal L}^{-1}"
  1410. InvL/: Format[ InvL[s_, t_], TeXForm ] := StringForm[ "{\\cal L}^{-1}_{``}", s ]
  1411.  
  1412. (*  InvZ  [Myers, 221]  *)
  1413. InvZ/: InvZ[zi_] := InvZ[zi, DummyVariables[Length[zi], Global`n]]
  1414. InvZ/: InvZ[z_, ni_] [ Z[n_, z_] [f_] ] :=
  1415.     If [ SameQ[ni, n], f, f /. ReplaceWith[n, ni] ] /;
  1416.     Length[n] == Length[ni]
  1417.  
  1418. InvZ/: Format[ InvZ[z_, n_], TeXForm ] := "{\\cal Z}^{-1}"
  1419. InvZ/: Format[ InvZ[z_, n_], TeXForm ] := StringForm[ "{\\cal Z}^{-1}_{``}", z ]
  1420.  
  1421. (*  L  *)
  1422. L/: L[t_] := L[t, DummyVariables[Length[t], Global`s]]
  1423. L/: L[t_, s_] [ InvL[si_, t_] [f_] ] :=
  1424.     If [ SameQ[s, si], f, f /. ReplaceWith[si, s] ] /;
  1425.     Length[s] == Length[si]
  1426.  
  1427. L/: L^-1[a__] := InvL[a]
  1428.  
  1429. L/: Format[ L, TeXForm ] := "{\\cal L}"
  1430. L/: Format[ L[t_, s_], TeXForm ] := StringForm[ "{\\cal L}_{``}", t ]
  1431.  
  1432. (*  LineImpulse  *)
  1433. Unprotect[samecoefficient];
  1434. Unprotect[mergecoefficient];
  1435.  
  1436. SetAttributes[samecoefficient, Listable];
  1437. samecoefficient[c1_, c2_] :=
  1438.     If [ SameQ[c1,c2],
  1439.          ! SameQ[c1, Null],
  1440.          SameQ[c1, Null] || SameQ[c2, Null] ]
  1441.  
  1442. SetAttributes[mergecoefficient, Listable];
  1443. mergecoefficient[c1_, c2_] := 
  1444.     Which [ SameQ[c1, Null], c2,
  1445.         SameQ[c2, Null], c1,
  1446.         True,            c1 ]
  1447.  
  1448. Protect[samecoefficient];
  1449. Protect[mergecoefficient];
  1450.  
  1451. LineImpulseMerge[nlist_, ncoeffs_, klist_, kcoeffs_] :=
  1452.     Block [    {commonvars, kscale, nscale, scaledkcoeffs, scaledncoeffs},
  1453.         scaledncoeffs = ncoeffs;
  1454.         scaledkcoeffs = kcoeffs;
  1455.         commonvars = Intersection[nlist, klist];
  1456.         If [ ! EmptyQ[commonvars],
  1457.              normvar = First[commonvars];
  1458.              nscale = AssociateItem[normvar, nlist, ncoeffs];
  1459.              scaledncoeffs = ncoeffs / nscale;
  1460.              kscale = AssociateItem[normvar, klist, kcoeffs];
  1461.              scaledkcoeffs = kcoeffs / kscale ];
  1462.         allvars = Union[nlist, klist];
  1463.         coeffs1 = AssociateItem[allvars, nlist, scaledncoeffs];
  1464.         coeffs2 = AssociateItem[allvars, klist, scaledkcoeffs];
  1465.         { Apply[And, samecoefficient[coeffs1, coeffs2]],
  1466.           LineImpulse[allvars, mergecoefficient[coeffs1, coeffs2]] } ]
  1467.  
  1468. LineImpulse/: LineImpulse[n_?AtomQ, c_] := Impulse[c n]
  1469.  
  1470. LineImpulse/: LineImpulse[nlist_, ncoeffs_] LineImpulse[klist_, kcoeffs_] :=
  1471.     LineImpulseMerge[nlist, ncoeffs, klist, kcoeffs] [[2]] /;
  1472.     ! EmptyQ[Intersection[nlist,klist]] && LineImpulseMerge[nlist, ncoeffs, klist, kcoeffs] [[1]]
  1473.  
  1474. LineImpulse/: TheFunction[ LineImpulse[nlist_, ncoeffs_] ] :=
  1475.     Impulse[ Apply[Plus, nlist, ncoeffs] ]
  1476.  
  1477. LineImpulse/: N [ LineImpulse[nlist_, ncoeffs_] ] :=
  1478.     N [ TheFunction[ LineImpulse[nlist, ncoeffs] ] ]
  1479.  
  1480. LineImpulse/: Format[ LineImpulse[nlist_List, ncoeffs_List] ] :=
  1481.     Format[Impulse[Apply[Plus, nlist ncoeffs]]] /;
  1482.     Length[nlist] == Length[ncoeffs]
  1483.  
  1484. (*  OperatorInOperExpr  *)
  1485. OperatorInOperExpr[ h_[a__][s__] ] := h[a]
  1486. OperatorInOperExpr[ h_[s__] ] := h
  1487.  
  1488. (*  OperatorName  *)
  1489. OperatorName[ h_[a__][s__] ] := h
  1490. OperatorName[ h_[a__] ] := h
  1491. OperatorName[ x_ ] := x
  1492.  
  1493. (*  ParametersInOperExpr  *)
  1494. ParametersInOperExpr[ h_[a__][s__] ] := a
  1495. ParametersInOperExpr[ h_[s__] ] := Null
  1496.  
  1497. (*  Periodic  *)
  1498. Periodic/: Format[ Periodic[k_, n_] ] := informat[Periodic, k, n]
  1499. Periodic/: Format[ Periodic[k_, n_], TeXForm ] := inTeXformat[Perodic, k, n]
  1500.  
  1501. Periodic/: GetOperatorVariables[ Periodic[k_, n_] ] := n
  1502.  
  1503. (*  PolyphaseDownsample  *)
  1504. PolyphaseDownsample/: GetOperatorVariables[ PolyphaseDownsample[m_, h_, n_] ] := n
  1505.  
  1506. (*  PolyphaseUpsample  *)
  1507. PolyphaseUpsample/: GetOperatorVariables[ PolyphaseUpsample[l_, h_, n_] ] := n
  1508.  
  1509. (*  Pulse  *)
  1510. Pulse[l_] := Pulse[l, Global`n]                (* default args    *)
  1511.  
  1512. Pulse[0, n_] := 0                     (* definition      *)
  1513. Pulse[L_, 0] := 1
  1514. Pulse[1, n_] := Impulse[n]
  1515. Pulse[Infinity, n_] := Step[n]
  1516. Pulse/: Pulse[l_, n_] := 1 /; N[0 <= n < l]
  1517. Pulse/: Pulse[l_, n_] := 0 /; N[( n < 0 ) || ( n >= l )]
  1518.  
  1519. Pulse/: TheFunction[Pulse[l_, n_]] := Step[n] - Step[n - l]
  1520.  
  1521. Pulse/: Extent1D[ Pulse[l_, a_. n_ + b_.], n_ ] :=
  1522.         Extent1DOrder[-b/a, (l-b)/a] /;
  1523.         FreeQ[{a,b,l}, n]
  1524.  
  1525. Pulse/: Format[ Pulse[l_, n_] ] :=            (* output forms    *)
  1526.         Format[ Pulse Subscript[l] [n] ]
  1527.  
  1528. Pulse/: Format[ Pulse, TeXForm ] := "\\sqcap"
  1529. Pulse/: Format[ Pulse[l_, n_], TeXForm ] :=
  1530.         StringForm[ "\\sqcap_{``} [``]", l, n ]
  1531.  
  1532. Derivative[0,1][Pulse] :=                (* derivative rule *)
  1533.     ( Impulse[#2] + Impulse[#2 - #1] )&
  1534.  
  1535. (*  RationalGCD  *)
  1536. RationalGCD[ ] := 0
  1537. RationalGCD[ x_ ] := rationalGCD[{x}]
  1538. RationalGCD[ arg_, rest__ ] := rationalGCD[ {arg, rest} ]
  1539.  
  1540. rationalGCD[ numlist_List ] :=
  1541.     Block [    {denomgcd, gcdfun, gcdlist, newlist, numergcd},
  1542.         newlist = Flatten[numlist];
  1543.         gcdlist = Map[ gcdfilter, newlist ];
  1544.         gcdfun = If [ TrueQ[$VersionNumber >= 2.0],
  1545.                   PolynomialGCD, GCD ];
  1546.         numergcd = Apply[gcdfun, Map[Numerator, gcdlist]];
  1547.         denomgcd = Apply[gcdfun, Map[Denominator, gcdlist]];
  1548.         numergcd / denomgcd ]
  1549.  
  1550. (*  Rev  *)
  1551. Rev/: Rev[n_][Rev[n_][x_]] := x
  1552. Rev/: Rev[n_][Rev[m_][x_]] :=
  1553.     Block [    {remaining},
  1554.         remaining = SetExclusion[ToList[n], ToList[m]];
  1555.         Which [ EmptyQ[remaining],
  1556.               x,
  1557.             SameQ[Length[remaining], 1],
  1558.               Rev[ remaining[[1]] ] [x],
  1559.             True,
  1560.               Rev[remaining][x] ] ] /;
  1561.     ! EmptyQ[Intersection[ToList[n], ToList[m]]]
  1562.  
  1563. Rev/: Extent1D[ Rev[n_][f_], n_ ] :=
  1564.     Block [    {extent},
  1565.         extent = Extent1D[f, n];
  1566.         { -Second[extent], -First[extent] } ]
  1567.  
  1568. Rev/: TheFunction[Rev[n_][x_]] := ( TheFunction[x] /. n ~ReplaceWith~ (-n) )
  1569. Rev/: N[ Rev[n_][x_] ] := N [ TheFunction[Rev[n][x]] ]
  1570.  
  1571. Rev/: Format[ Rev[n_] ] := Format[ Subscripted[Rev[n]] ]
  1572. Rev/: Format[ Rev[n_], TeXForm ] := Format[ Subscripted[Rev[n]] ]
  1573.  
  1574. (*  RewriteSummations  *)
  1575. donotrewrite[f_, t_] := FreeQ[f, Summation] && FreeQ[f, Periodic[k_,t] ]
  1576.  
  1577. rewriteFindLimits[ x_, t_, tlower_, tupper_ ] :=
  1578.     Block [    {ext, tl, tu},
  1579.         ext = Extent1D[x, t];
  1580.         tl = mymax[ext[[1]], tlower];
  1581.         tu = mymin[ext[[2]], tupper];
  1582.         {tl, tu} ]
  1583.  
  1584. RewriteSummations[ f_, t_, tl_, tu_ ] := f /; donotrewrite[f, t]
  1585.  
  1586. RewriteSummations[ f_, t_, tlower_, tupper_ ] := 
  1587.     Block [    {ext, ii, tl, tu},
  1588.         SPSimplify[
  1589.           f /.
  1590.             { x_. Periodic[k_, v_][g_] :>         (* use v_ not t *)
  1591.             Block [ {},
  1592.               {tl, tu} = rewriteFindLimits[x, t, tlower, tupper];
  1593.               x rewriteonesummation[ Simplify[g /. (t -> t + ii k)],
  1594.                              True, t, tl, tu, ii,
  1595.                          -Infinity, Infinity, 1 ] ] /;
  1596.              SameQ[v, t] && donotrewrite[g, t],
  1597.               x_. Summation[i_, il_, iu_, inc_][g_] :>
  1598.             Block [ {},
  1599.               {tl, tu} = rewriteFindLimits[x, t, tlower, tupper];
  1600.               x rewriteonesummation[ Simplify[g], False, t, tl, tu,
  1601.                          i, il, iu, inc ] ] /;
  1602.              donotrewrite[g, t] },
  1603.           Variables -> t ] ]
  1604.  
  1605. rewriteonesummation[ a_ + b_, flag_, t_, tl_, tu_, i_, il_, iu_, inc_ ] :=
  1606.     rewriteonesummation[a, flag, t, tl, tu, i, il, iu, inc] +
  1607.     rewriteonesummation[b, flag, t, tl, tu, i, il, iu, inc]
  1608.  
  1609. rewriteonesummation[ g_, periodicflag_, t_, tl_, tu_, i_, il_, iu_, inc_ ] :=
  1610.     Block [ {ext, il0, ilact, intflag, iu0, iuact,
  1611.          lext, lsol, retval, solutions, uext, usol, valid},
  1612.         intflag = IntegerQ[inc] &&    (* index var i is an integer *)
  1613.               ( IntegerQ[il] || SameQ[il, -Infinity] ) &&
  1614.               ( IntegerQ[iu] || SameQ[iu, Infinity] );
  1615.         ext = Simplify[ Extent1D[g, t] ] // minmaxSimplify;
  1616.         valid = ListQ[ext] && SameQ[Length[ext], 2];
  1617.         If [ ! valid, ext = { -Infinity, Infinity } ];
  1618.  
  1619.         {lext, uext} = ext;
  1620.         If [ FreeQ[lext, i] && ! FreeQ[uext, i], lext = uext ];
  1621.         If [ FreeQ[uext, i] && ! FreeQ[lext, i], uext = lext ];
  1622.  
  1623.         If [ FreeQ[lext, i] && FreeQ[uext, i],
  1624.              Message[ Summation::extent ];
  1625.                retval = If [ periodicflag,
  1626.                      g /. i -> 0,
  1627.                      Summation[i, il, iu, inc][g] ],
  1628.  
  1629.              lsol = Solve[ lext == tu, i ];
  1630.              usol = Solve[ uext == tl, i ];
  1631.              Which [ SameQ[Head[lsol], Solve] ||
  1632.                  SameQ[Head[usol], Solve],
  1633.                    Message[ Summation::extent ];
  1634.                      retval = If [ periodicflag,
  1635.                           g /. i -> 0,
  1636.                           Summation[i, il, iu, inc][g] ],
  1637.  
  1638.                  intflag,
  1639.                    solutions = N[ Join[ i /. lsol, i /. usol ] ];
  1640.                        il0 = Min[solutions];
  1641.                        iu0 = Max[solutions];
  1642.                        ilact = Max[il, Ceiling[Min[il0, iu0]]];
  1643.                        iuact = Min[iu, Max[il0, iu0]];
  1644.                        retval = Sum[ g, {i, ilact, iuact, inc} ],
  1645.  
  1646.                  False,
  1647.                    solutions = Join[ i /. lsol, i /. usol ];
  1648.                        il0 = Apply[Min, solutions] // minmaxSimplify;
  1649.                        iu0 = Apply[Max, solutions] // minmaxSimplify;
  1650.                        ilact = Max[il, Min[il0, iu0]] // minmaxSimplify;
  1651.                        iuact = Min[iu, Max[il0, iu0]] // minmaxSimplify;
  1652.                    If [ InfinityQ[il],
  1653.                             ilact = ilact - Mod[ilact, inc];
  1654.                               iuact = iuact - Mod[iuact, inc],
  1655.                             ilact = ilact - Mod[ilact - il, inc];
  1656.                               iuact = iuact - Mod[iuact - il, inc] ];
  1657.                        retval = Sum[ g, {i, ilact, iuact, inc} ] ] ];
  1658.     retval ]
  1659.  
  1660.  
  1661. (*  ScaleAxis [Myers, 220]  *)
  1662. ScaleAxis/: TheFunction[ScaleAxis[l_, w_Symbol][x_]] :=
  1663.         TheFunction[x] /. w -> l w
  1664. ScaleAxis/: TheFunction[ScaleAxis[{l__},{w__}][x_]] :=
  1665.         ( TheFunction[x] /. {w} ~ReplaceWith~ ({l} . {w}) )
  1666.  
  1667. ScaleAxis/: N[ ScaleAxis[l_, w_][x_] ] := N[ TheFunction[ ScaleAxis[l,w][x] ] ]
  1668.  
  1669. ScaleAxis/: Format[ ScaleAxis[l_,w_] ] := informat[ScaleAxis, l, w]
  1670. ScaleAxis/: Format[ ScaleAxis[l_,w_], TeXForm ] := inTeXformat[ScaleAxis, l, w]
  1671.  
  1672. ScaleAxis/: GetOperatorVariables[ ScaleAxis[l_, w_] ] := w
  1673.  
  1674. (*  ScalingFactor --  must be independent of variable z  *)
  1675. ScalingFactor[f_, z_] :=
  1676.     breakup[ Apply[ RationalGCD, GetAllFactors[f, z] ], z ]
  1677.  
  1678. (*  SequencePlot  *)
  1679. Options[ SequencePlot ] :=
  1680.     { Axes -> axesdefaultvalue,
  1681.       DisplayFunction :> $DisplayFunction,
  1682.       PlotLabel -> "Sequence Plot",
  1683.       PlotRange -> All }
  1684.  
  1685. baseticks = { 1, 2, 2, 5, 5, 5, 5, 5, 10, 10 };
  1686. getticks[nstart_, nend_] :=
  1687.     Block [    {factor, i, ninc, ns, nterm},
  1688.         ninc = Round[(nend - nstart) / 5];
  1689.         If [ ninc == 0, ninc = 1 ];
  1690.         If [ ninc > 2,
  1691.              factor = 10;
  1692.              While [ ninc > factor, factor *= 10 ];
  1693.              factor /= 10;
  1694.              nterm = intdivide[ninc, factor];
  1695.              ninc = factor * baseticks[[nterm]] ];
  1696.         ns = Sign[nstart] ninc intdivide[Abs[nstart], ninc];
  1697.         Table[i, {i, ns, nend, ninc}] ]
  1698.  
  1699. dgetvalue[f_, n_Symbol, n0_Integer] := GetValue[f, n, n0]
  1700. dgetvalue[f_, n_Symbol, n0_Real] := GetValue[f, n, Round[n0]]
  1701. dgetvalue[f_, {n1_Symbol, n2_Symbol}, {n01_?NumberQ, n02_?NumberQ}] :=
  1702.     GetValue[f, {n1, n2}, {Round[n01], Round[n02]}]
  1703.  
  1704. SequencePlot[f_List, {n1_Symbol, st1_, end1_},
  1705.              {n2_Symbol, st2_, end2_}, op___] :=
  1706.     MyMessage[ SequencePlot::nolist, NullPlot ]
  1707.  
  1708. SequencePlot[f_, {n1_Symbol, st1_, end1_}, {n2_Symbol, st2_, end2_}, op___] :=
  1709.     Block [    {funct, ftemp, funs, n1length, n2length, n1str, n2str,
  1710.          n1temp, n2temp, nstart, nend, oplist, plot},
  1711.  
  1712.         nstart = Floor[N[{st1, st2}]];
  1713.         nend   = Ceiling[N[{end1, end2}]];
  1714.         n1length = nend[[1]] - nstart[[1]];
  1715.         n2length = nend[[2]] - nstart[[2]];
  1716.         n1str = StripPackage[n1];
  1717.         n2str = StripPackage[n2];
  1718.         oplist = Join [    ToList[op],
  1719.                 Options[SequencePlot],
  1720.                 { PlotPoints -> {n1length + 1, n2length + 1},
  1721.                   AxesLabel -> {n1str, n2str, " "},
  1722.                   Ticks -> Automatic } ];
  1723.  
  1724.         funct = ToDiscrete[f];
  1725.         ftemp = N[ TheFunction[ funct ] ];
  1726.  
  1727.         (*  Generate three-dimensional coordinates for plot  *)
  1728.         Off[Power::infy, Infinity::indt];
  1729.         plot = Apply[ Plot3D,
  1730.                   Join[ { dgetvalue[ ftemp, {n1, n2},
  1731.                          {n1temp, n2temp} ],
  1732.                       { n1temp, nstart[[1]], nend[[1]] },
  1733.                       { n2temp, nstart[[2]], nend[[2]] } },
  1734.                     oplist ] ];
  1735.         On[Power::infy, Infinity::indt];
  1736.  
  1737.         plot ]
  1738.  
  1739.  
  1740. SequencePlot[f_, {n_Symbol, start_, end_}, op___] :=
  1741.     Block [    {factor, ftemp, funct, funs, length, linethickness,
  1742.          nend, nstart, nstr, ntemp, oplist, plot,
  1743.          pointthickness, showoptions},
  1744.  
  1745.         nstart = Floor[N[start]];
  1746.         nend   = Ceiling[N[end]];
  1747.  
  1748.         (*  Set up the options  *)
  1749.         nticks = getticks[nstart, nend];
  1750.         nstr = StripPackage[n];
  1751.         oplist = Join [    Flatten[ToList[op]],
  1752.                 Options[SequencePlot],
  1753.                     { AxesLabel -> { nstr, " " },
  1754.                   Ticks -> { nticks, Automatic } } ];
  1755.  
  1756.         factor = N[ Log[10, nend - nstart + 3 ] ];
  1757.         linethickness = 0.008 / factor;
  1758.         pointthickness = 0.024 / factor;
  1759.  
  1760.         (*  Extract the functional form of the expression  *)
  1761.         funct = ToDiscrete[f];
  1762.         ftemp = N[ TheFunction[ funct ] ];
  1763.  
  1764.         (*  Handle any infinite summations  *)
  1765.         ftemp = RewriteSummations[ftemp, n, nstart, nend];
  1766.  
  1767.         (*  Generate form for 1-D function  *)
  1768.         SetAttributes[seqFun1D, Listable];    (* avoid fun pointers *)
  1769.         seqFun1D[g_] :=
  1770.             DiscreteGraphics [
  1771.                 Table [ {ntemp, dgetvalue[g, n, ntemp]},
  1772.                     {ntemp, nstart, nend}],
  1773.                 linethickness,
  1774.                 pointthickness ];
  1775.  
  1776.         (*  Plot "time"-domain    *)
  1777.         Off[Power::infy, Infinity::indt];
  1778.         showoptions = RemoveOptions[oplist, specialPlotOptions];
  1779.         plot = Show [ seqFun1D[ftemp], showoptions ];
  1780.         On[Power::infy, Infinity::indt];
  1781.  
  1782.         plot ]
  1783.  
  1784. (*  SequenceToFunction  *)
  1785. SequenceToFunction[seq_, n_:Global`n, noffset_:0] :=
  1786.     Block [ {},
  1787.         (* Variable no. of arguments -- could not use Function *)
  1788.         impulsegen[l__] := seq[[l]] Apply[Impulse,
  1789.                           n - {l} - noffset + 1];
  1790.         Apply[ Plus, Flatten [ Array[impulsegen, Dimensions[seq]] ] ] ]
  1791.  
  1792. (*  SignalCleanup  *)
  1793. SignalCleanup[funct_, t_Symbol, nstart_, nend_] :=
  1794.     Block [    {deltafuns, ftemp},
  1795.  
  1796.         (*  Separate delta functions from rest of funct     *)
  1797.         (*  DeltaPlot handles Summation operators by itself *)
  1798.  
  1799.         deltafuns = GetDeltaFunctions[funct, t];
  1800.         ftemp = funct //.
  1801.             { h_[ c_. Delta[a_. t + b_.] ] :> 0,
  1802.               h_[ c_. Delta[a_. t + b_.] + x_ ] :> h[x],
  1803.               Delta[a_. t + b_.] :> 0 };
  1804.  
  1805.         (*  Convert function into plottable functional form  *)
  1806.  
  1807.         ftemp = N[ TheFunction[ftemp] ];
  1808.  
  1809.         (*  Rewrite infinite summations and periodic operators  *)
  1810.  
  1811.         deltafuns = RewriteSummations[deltafuns, t, nstart, nend];
  1812.         ftemp = RewriteSummations[ftemp, t, nstart, nend];
  1813.  
  1814.         { deltafuns, ftemp } ]
  1815.  
  1816.  
  1817. SignalCleanup[funct_, {t1_Symbol, t2_Symbol}, nstart_, nend_] :=
  1818.     Block [    {deltafuns, ftemp},
  1819.  
  1820.         (*  Separate delta functions from rest of funct  *)
  1821.  
  1822.         deltafuns = GetDeltaFunctions[funct, {t1, t2}];
  1823.         ftemp = funct //.
  1824.             { h_[ c_. Delta[a_. t1 + b_.] ] :> 0,
  1825.               h_[ c_. Delta[a_. t1 + b_.] + x_ ] :> h[x],
  1826.               Delta[a_. t1 + b_.] :> 0,
  1827.               h_[ c_. Delta[a_. t2 + b_.] ] :> 0,
  1828.               h_[ c_. Delta[a_. t2 + b_.] + x_ ] :> h[x],
  1829.               Delta[a_. t2 + b_.] :> 0 };
  1830.  
  1831.         (*  Convert freq. response into plottable function form  *)
  1832.  
  1833.         ftemp = N [ TheFunction[funct] ];
  1834.  
  1835.         { deltafuns, ftemp } ]
  1836.  
  1837. (*  SignalPlot  *)
  1838. specialPlotOptions =
  1839.     Complement[ Sort[ Map[First, Options[Plot]] ],
  1840.             Sort[ Map[First, Options[Graphics]] ] ]
  1841.  
  1842. sigPlot1D[args__][g_] := SignalPlot[g, args]
  1843.  
  1844. Options[ SignalPlot ] :=
  1845.     { Axes -> axesdefaultvalue,
  1846.       DisplayFunction :> $DisplayFunction,
  1847.       PlotLabel -> "Signal Plot",
  1848.       PlotRange -> All,
  1849.       Ticks -> Automatic }
  1850.  
  1851. SignalPlot[ f_List, {t1_Symbol, start1_, end1_},
  1852.             {t2_Symbol, start2_, end2_}, op___ ] :=
  1853.     MyMessage[ SignalPlot::nolist, NullPlot ]
  1854.  
  1855. SignalPlot[ f_,    {t1_Symbol, start1_, end1_},
  1856.         {t2_Symbol, start2_, end2_}, op___ ] :=
  1857.     Block [    {deltafuns, freqresp, ftemp, funct, oplist,
  1858.          t1str, t2str, t1temp, t2temp},
  1859.  
  1860.         (*  Set up for plotting  *)
  1861.         t1str = StripPackage[t1];
  1862.         t2str = StripPackage[t2];
  1863.         oplist = Join[ ToList[op],
  1864.                    { AxesLabel -> { t1str, t2str, " " } },
  1865.                    Options[ SignalPlot ] ];
  1866.  
  1867.         (*  Make function continuous and replace non-sep delta's *)
  1868.         funct = ToContinuous[f] /.
  1869.              Delta[a_. t1 + b_. t2 + c_.] :> Impulse[a t1 + b t2 + c];
  1870.  
  1871.         (*  Separate delta functions from rest of funct and      *)
  1872.         (* convert the non-delta expressions into plottable form *)
  1873.         { deltafuns, ftemp } =
  1874.             SignalCleanup[ funct, {t1,t2},
  1875.                        N[{start1, start2}], N[{end1, end2}] ];
  1876.  
  1877.         (*  Plot delta functions separately from rest of function  *)
  1878.  
  1879.         Plot3D[ GetValue[ftemp, {t1, t2}, {t1temp, t2temp}],
  1880.             { t1temp, start1, end1 },
  1881.             { t2temp, start2, end2 },
  1882.             Release[oplist] ] ]
  1883.  
  1884. SignalPlot[f_List, {t_Symbol, start_, end_}, op___] :=
  1885.     Block [    {fun, oplist, showoptions, theplots},
  1886.         fun = sigPlot1D[{t,start,end}, DisplayFunction->Identity, op];
  1887.         theplots = Map[ fun, f ];
  1888.         oplist = Join[ToList[op], Options[SignalPlot]];
  1889.         showoptions = RemoveOptions[oplist, specialPlotOptions];
  1890.         Show[ theplots, ToCollection[showoptions] ] ]
  1891.  
  1892. SignalPlot[f_, {t_Symbol, start_, end_}, op___] :=
  1893.     Block [    {deltafuns, ftemp, i, imstyle,
  1894.          nend = N[end], nstart = N[start], oplist,
  1895.          plot, showoptions, restyle, tstr, ttemp },
  1896.  
  1897.         (*  Set up for plotting  *)
  1898.  
  1899.         tstr = StripPackage[t];
  1900.         restyle = Thickness[0.006];
  1901.         imstyle = Dashing[{0.05,0.05}]; 
  1902.         oplist = Join[ ToList[op],
  1903.                    { AxesLabel -> { tstr, " " },
  1904.                  DisplayFunction -> Identity,
  1905.                  PlotStyle -> { restyle, imstyle } },
  1906.                    Options[ SignalPlot ] ];
  1907.  
  1908.         (*  Separate delta functions from rest of funct and  *)
  1909.         (*  convert function into plottable functional form  *)
  1910.  
  1911.         { deltafuns, ftemp } =
  1912.             SignalCleanup[ ToContinuous[f], t, nstart, end ];
  1913.  
  1914.         (*  Plot delta functions separately from ftemp  *)
  1915.  
  1916.         Off[Power::infy, Infinity::indt];
  1917.  
  1918.         (*  1.  Generate the graphics for the entire signal  *)
  1919.  
  1920.         If [ ZeroQ[ftemp],
  1921.              plot = If [ ! AtomQ[deltafuns],   (* delta funs found *)
  1922.                  DeltaPlot[deltafuns, t, nstart, nend],
  1923.                  NullPlot ];
  1924.              plot = { Plot[ 0,
  1925.                     { ttemp, nstart, nend},
  1926.                     Release[oplist] ],
  1927.                   plot },
  1928.  
  1929.              plot = Plot[ { Re[GetValue[ftemp, t, ttemp]],
  1930.                     Im[GetValue[ftemp, t, ttemp]] },
  1931.                   { ttemp, nstart, nend },
  1932.                   Release[oplist] ];
  1933.              If [ ! AtomQ[deltafuns],      (* delta funs found *)
  1934.                   plot = DeltaPlot[deltafuns, t, nstart, nend, plot]] ];
  1935.  
  1936.         (*  2.  Plot the entire signal  *)
  1937.  
  1938.         oplist = Join[ ToList[op], Options[SignalPlot] ];
  1939.         showoptions = RemoveOptions[oplist, specialPlotOptions];
  1940.  
  1941.         plot = Show[ plot, ToCollection[showoptions] ];
  1942.  
  1943.         On[Power::infy, Infinity::indt];
  1944.  
  1945.         plot ]
  1946.  
  1947.  
  1948. (*  SignalsInOperExpr  *)
  1949. SignalsInOperExpr[ h_[s__] ] := s
  1950. SignalsInOperExpr[ h_[a__][s__] ] := s
  1951.  
  1952. SignalsInOperExpr[ h_[s__], h_ ] := s
  1953. SignalsInOperExpr[ h_[s__], op_ ] := h[s]        /; ! SameQ[h, op]
  1954.  
  1955. SignalsInOperExpr[ h_[a__][s__], h_ ] := s
  1956. SignalsInOperExpr[ h_[a__][s__], op_ ] := h[a][s]    /; ! SameQ[h, op]
  1957.  
  1958. (*  Shift [Myers, 217]  *)
  1959. Shift/: Shift[m_, n_List] := Shift[ Table[m, Length[n]], n ] /; ! ListQ[m]
  1960.  
  1961. Shift/: Shift[m_List, n_List][x_] := MyMessage[ Shift::badmD, x ] /;
  1962.     Length[m] != Length[n]
  1963.  
  1964. Shift/: Shift[0, n_][x_] := x
  1965.  
  1966. Shift/: Extent1D[ Shift[m_, n_][f_], n_ ] := Extent1D[f, n] + m
  1967.  
  1968. Shift/:    TheFunction[Shift[k_,n_][x_]] :=
  1969.     ( TheFunction[x] /. n ~ReplaceWith~ (n - k) )
  1970. Shift/: N[ Shift[k_,n_][x_] ] := N [ TheFunction[ Shift[k,n][x] ] ]
  1971.  
  1972. Shift/: Format[ Shift[m_,n_] ] := informat[Shift, m, n]
  1973. Shift/: Format[ Shift[m_,n_], TeXForm ] := inTeXformat[Shift, m, n]
  1974.  
  1975. Shift/: GetOperatorVariables[ Shift[l_, n_] ] := n
  1976.  
  1977.  
  1978. (*  Sinc  *)
  1979. Sinc/: Sinc[-Infinity] := 0
  1980. Sinc/: Sinc[0] := 1
  1981. Sinc/: Sinc[0.] := 1.
  1982. Sinc/: Sinc[Infinity] := 0
  1983.  
  1984. Sinc/: Sinc[x_?NumberQ] := Sin[x] / x
  1985.  
  1986. Sinc/: Sinc[x_, y__] := Sinc[x] Sinc[y]
  1987.  
  1988. Sinc/: Format[Sinc, TeXForm] := "{\\rm sinc}"
  1989.  
  1990. Sinc/: Derivative[1][Sinc] := (( Cos[#1] / #1 ) - ( Sinc[#1] / #1 ))&
  1991.  
  1992.  
  1993. (*  SPSimplify  *)
  1994. Options[SPSimplify] :=
  1995.     Join[{ Dialogue -> False, Variables -> {} }, Options[Simplify]]
  1996.  
  1997. kludgeRules =   (* prevents infinite loop in Mathematica 2.0 and lower *)
  1998.       {    a1_. x_. Exp[Complex[0, i1_] th1_.] +
  1999.         a2_. x_. Exp[Complex[0, i2_] th2_.] :>
  2000.         2 x Abs[a1] Cos[Arg[a1] + i1 th1] /;
  2001.         ( SameQ[a1, Conjugate[a2]] && SameQ[i1 th1, -i2 th2] ),
  2002.         a1_. x_. Exp[Complex[0, i1_] th1_.] +
  2003.         a2_. x_. Exp[Complex[0, i2_] th2_.] :>
  2004.         2 I x Abs[a2] Sin[Arg[a2] + i2 th2] /;
  2005.         ( SameQ[a1, -a2] && SameQ[i1 th1, -i2 th2] ) }
  2006.  
  2007. SPSimplify[ x_, op___ ] :=
  2008.     Block [    {dialflag, different, laste, newe, oplist,
  2009.          trig, varrules, varflag, variables},
  2010.         oplist = ToList[op] ~Join~ Options[SPSimplify];
  2011.         trig = Replace[Trig, oplist];
  2012.         dialflag = InformUserQ[oplist];
  2013.         variables = Replace[Variables, oplist];
  2014.         varflag = ! EmptyQ[variables];
  2015.         If [ varflag,
  2016.              varrules = makesimplifyrules[variables] ];
  2017.  
  2018.         newe = x;
  2019.         different = True;
  2020.         While [ different,
  2021.             laste = newe;
  2022.             If [ ! EmptyQ[ kludgeRules ],
  2023.                  newe = newe /. kludgeRules ];
  2024.             newe = If [ TrueQ[ $VersionNumber >= 2.0 ],
  2025.                     Simplify[newe, Trig -> trig],
  2026.                     Simplify[newe] ];
  2027.             newe = newe /. SPSimplificationRules;
  2028.             If [ varflag, newe = newe /. varrules ];
  2029.             different = ! SameQ[laste, newe];
  2030.             If [ dialflag && different,
  2031.                  Print["which simplifies to"]; Print[newe] ] ];
  2032.         newe ]
  2033.  
  2034. makesimplifyrules[var_Symbol] := makesimplifyrules[var, {}]
  2035. makesimplifyrules[var1_Symbol, var2_Symbol, rest___] :=
  2036.     makesimplifyrules[{var1, var2, rest}]
  2037. makesimplifyrules[varlist_List] :=
  2038.     Apply[ Join,
  2039.            Map[ makesimplifyrules[#,
  2040.                       Complement[varlist, ToList[#]]]&,
  2041.                       varlist] ]
  2042. makesimplifyrules[t_, varlist_] :=
  2043.     { Delta[a_ t + b_.] :> Delta[t + b/a] / Abs[a] /;
  2044.         FreeQ[a, t] && MyFreeQ[b, varlist],
  2045.       d_. (y_. + amp1_. Delta[t + t0_.]) :>
  2046.         d y + Limit[TheFunction[d amp1], t -> -t0] Delta[t + t0] /;
  2047.         FreeQ[t0, t] && (! FreeQ[d amp1, t]) &&
  2048.         MyFreeQ[t0, varlist] &&
  2049.           ! InfinityQ[ Limit[TheFunction[d amp1], t -> -t0] ],
  2050.       c_. Sign[b_. t] + c_ :> 2 c CStep[b t] /;
  2051.         FreeQ[b, t],
  2052.       CStep[a_ t + b_.] :> CStep[t + b/a] / Abs[a] /;
  2053.         Positive[a] && FreeQ[a, t] && MyFreeQ[b, varlist],
  2054.       CStep[a_ t + b_.] :> CStep[-t - b/a] / Abs[a] /;
  2055.         Negative[a] && FreeQ[a, t] && MyFreeQ[b, varlist] }
  2056.  
  2057. (*  Step  *)
  2058. Step/: Step[Infinity] := 1                (* definition        *)
  2059. Step/: Step[t_] := 1        /; N[ t > 0 ]
  2060. Step/: Step[t_] := 0        /; N[ t < 0 ]
  2061. Step/: Step[0] := 1
  2062. Step/: Step[0.] := 1
  2063. Step/: Step[-Infinity] := 0
  2064.  
  2065. Step/: Extent1D[ Step[a_. n_ + b_.], n_ ] :=
  2066.         Extent1DOrder[-b/a, Sign[a] Infinity] /;
  2067.         FreeQ[{a,b}, n]
  2068.  
  2069. Step/: Step[t_, args__] := Step[t] Step[args]        (* multidimensional *)
  2070. Step/: Step[List[args__]] := Step[args]            (* separability        *)
  2071.  
  2072. Step/: Step[t_]^a_ := Step[t]                (* automatic        *)
  2073. Step/: Step[n_Symbol + m_.] Step[n_Symbol  + k_.] :=    (* simplification   *)
  2074.     Step[n + Min[m,k]] /;                (* rules        *)
  2075.     NumberQ[m] && NumberQ[k]
  2076. Step/: Step[n_Symbol + m_.] Step[-n_Symbol + k_.] :=
  2077.     Pulse[k + m, n + m] /;
  2078.     N[ -m <= k ]
  2079. Step/: Step[n_Symbol + m_.] Step[-n_Symbol + k_.] := 0 /;
  2080.     N[ -m > k ]
  2081.  
  2082. Step/: Simplify[Step[a_ n_Symbol + b_.]] :=        (* man. simp. rules *)
  2083.     Step[n + b/a] /;
  2084.     MyFreeQ[{a,b}, n] && Implies[ NumberQ[N[a]], N[a > 0] ]
  2085. Step/: Simplify[Step[- a_ n_Symbol + b_.]] :=
  2086.     Step[-n + b/a] /;
  2087.     MyFreeQ[{a,b}, n] && Implies[ NumberQ[N[a]], N[a > 0] ]
  2088.  
  2089. Step/: Format[ Step[x_], TeXForm ] :=            (* output form      *)
  2090.     StringForm["u[``]", x]
  2091.  
  2092. Derivative[1][Step] := Impulse                (* derivative rule  *)
  2093.  
  2094. (*  Summation  *)
  2095. Summation/: Summation[i_Symbol, n_] := Summation[i, 1, n, 1]
  2096. Summation/: Summation[i_Symbol, istart_, iend_] :=
  2097.     Summation[i, istart, iend, 1]
  2098. Summation/: Summation[i_Symbol, istart_, iend_, inc_][0] := 0
  2099.  
  2100. Summation/: TheFunction[Summation[i_Symbol, istart_, iend_, inc_][f_]] :=
  2101.     Block [    {tempsym},
  2102.         If [ NumberQ[istart] && NumberQ[iend] && NumberQ[inc],
  2103.              Sum[ TheFunction[f /. i -> tempsym],
  2104.               {tempsym, istart, iend, inc} ],
  2105.              Summation[i, istart, iend, inc][ TheFunction[f] ] ] ]
  2106.  
  2107. Summation/: Extent1D[ Summation[i_, istart_, iend_, inc_][f_], n_ ] :=
  2108.     Block [    {extent},
  2109.         extent = Extent1D[f, n];
  2110.         Extent1DOrder[ extent /. i -> istart,
  2111.                    extent /. i -> iend ] ] /;
  2112.     FreeQ[{i,istart,iend,inc}, n]
  2113.  
  2114. Summation/: N[Summation[i_Symbol, istart_?NumberQ, iend_?NumberQ, inc_?NumberQ][f_]] :=
  2115.     Sum[ N[f], {i, istart, iend, inc} ]
  2116.  
  2117. Summation/: Format[ Summation[i_, istart_, iend_, 1], TeXForm ] :=
  2118.     StringForm[ "\\sum_{`` = ``}^{``}", i, istart, iend ]
  2119.  
  2120. Summation/: Format[ Summation[i_, istart_, iend_, inc_], TeXForm ] :=
  2121.     StringForm["\\sum_{``=``, `` = `` + ``}^{``}",
  2122.            i, istart, i, i, inc, iend]
  2123.  
  2124.     (* The following rules were suggested by John Mitchell *)
  2125. getdvars[ x_Symbol ] := x
  2126. getdvars[ {x_Symbol, k_} ] := x
  2127. Unprotect[D]
  2128. D/: D[expr_. Summation[i_, istart_, iend_, inc_][f_], x__] :=
  2129.     Summation[i, istart, iend, inc][ D[expr f, x] ] /;
  2130.     MyFreeQ[ i, Map[getdvars, {x}] ]
  2131. Protect[D]
  2132. Unprotect[Integrate]
  2133. Integrate/: Integrate[ expr_. Summation[i_, istart_, iend_, inc_][f_], x__] :=
  2134.      Summation[i, istart, iend, inc][ Integrate[expr f, x] ] /;
  2135.      MyFreeQ[ i, Map[getdvars, {x}] ]
  2136. Protect[Integrate]
  2137.  
  2138. (*  TheFunction  *)
  2139. TheFunction[x_?AtomQ] := x
  2140. TheFunction[Hold[x__]] := Hold[x]
  2141. TheFunction[Sign[x_]] := CStep[x] - CStep[-x]    (* Step or CStep will work  *)
  2142. TheFunction[h_[a_]] := h [ TheFunction[a] ]
  2143. TheFunction[h_[a1_, a__]] := Apply[ h, Map[TheFunction, { a1, a }] ]
  2144.  
  2145. (*  ToContinuous  *)
  2146. ToContinuous[expr_] := ReplaceRepeated[expr, ToContinuousRules]
  2147.  
  2148. ToContinuousRules =
  2149.      {
  2150.     Impulse[n_]   :> Delta[n],
  2151.     Step[n_]      :> CStep[n],
  2152.     Pulse[l_, n_] :> CPulse[l, n],
  2153.     Convolve[n_]  :> CConvolve[n]
  2154.      }
  2155.  
  2156. (*  ToDiscrete  *)
  2157. ToDiscrete[expr_] := ReplaceRepeated[expr, ToDiscreteRules]
  2158.  
  2159. ToDiscreteRules =
  2160.      {
  2161.     CStep[t_]      :> Step[t],
  2162.     Delta[t_]      :> Impulse[t],
  2163.     CPulse[l_, t_] :> Pulse[l, t],
  2164.     CConvolve[t_]  :> Convolve[t]
  2165.      }
  2166.  
  2167. (*  Unit *)
  2168. Unit/: Unit[0][t_] := Delta[t]                (* definition       *)
  2169. Unit/: Unit[-1][t_] := CStep[t]
  2170. Unit/: Unit[n_][t_?NumberQ] :=
  2171.      t^-(n + 1) / Factorial[-(n + 1)] CStep[t] /; N[n < 0]
  2172.  
  2173. Unit/: Extent1D[ Unit[n_Integer][a_. t_ + b_.], t_ ] := {-b/a, -b/a} /;
  2174.     FreeQ[{a,b}, t] && ( n <= 0 )
  2175. Unit/: Extent1D[ Unit[n_Integer][a_. t_ + b_.], t_ ] :=
  2176.     Extent1DOrder[ -b/a, Sign[a] Infinity ] /;
  2177.     FreeQ[{a,b}, t] && ( n > 0 )
  2178.  
  2179. Unit/: Unit[n_][List[args]] := Unit[n][args]        (* multidimensional *)
  2180. Unit/: Unit[n_][t1_, t__] := Unit[n][t1] Unit[n][t]    (* separability     *)
  2181.  
  2182. Unit/: TheFunction[Unit[n_][t__]] :=
  2183.      t^-(n + 1) / Factorial[-(n + 1)] CStep[t] /; N[n < 0]
  2184.  
  2185. Unit/: Format[ Unit[n_] ] := Subscripted[ Unit[n] ]    (* output forms     *)
  2186. Unit/: Format[ Unit[n_], TeXForm ] := StringForm[ "u_{``}", n ]
  2187.  
  2188. Derivative[1][Unit[n_]] := Unit[n+1]            (* derivative rule  *)
  2189.  
  2190. Unprotect[Integrate]                    (* integration rules *)
  2191. Integrate/: Integrate[ expr_. Unit[n_][a_. x_ + b_.], x_Symbol ] :=
  2192.     Limit[expr, x -> -b/a] Unit[n-1][a x + b] / a /;
  2193.     FreeQ[{a,b,c}, x]
  2194. Integrate/: Integrate[ expr_. Unit[n_][a_ x_ + b_.], {x_Symbol, x1_, x2_}] :=
  2195.     Integrate[expr Unit[n][x + b/a] / a, x] /;
  2196.     FreeQ[{a,b}, x]
  2197. Integrate/: Integrate[expr_. Unit[n_][x_ + c_.], {x_Symbol, x1_, x2_}] :=
  2198.     Limit[expr, x -> -c] CStep[-c - x1] CStep[c + x2] Unit[n-1][x + c] /;
  2199.     FreeQ[c, x]    (* CStep[-c - x1] CStep[c + x2] <--> x1 <= -c <= x2 *)
  2200. Protect[Integrate]
  2201.  
  2202. (*  Upsample [Myers, 218-219] [Bamberger, ch. 2]  *)
  2203.  
  2204.     (* Error checking of upsample parameters  *)
  2205.  
  2206. Upsample/: Upsample[m_List, n_List][f_] :=
  2207.     MyMessage[Upsample::convert, Upsample[DiagonalMatrix[m], n][f], m] /;
  2208.     VectorQ[m] && SameQ[Length[m], Length[n]]
  2209.  
  2210. Upsample/: Upsample[m_List, n_List][f_] :=
  2211.     MyMessage[Upsample::badmD, f] /;
  2212.     VectorQ[m] && ! SameQ[Length[m], Length[n]]
  2213.  
  2214. Upsample/: Upsample[m_List, n_List][f_] :=
  2215.     MyMessage[Upsample::badmD, f] /;
  2216.     MatrixQ[m] && ! Apply[SameQ, Append[Dimensions[m], Length[n]]]
  2217.  
  2218. Upsample/: Upsample[m_List, n_Symbol][f_] :=
  2219.     MyMessage[Upsample::badmD, f]
  2220.  
  2221.         (*  degenerate cases  *)
  2222.  
  2223. Upsample/: Upsample[1, n_][f_] := f
  2224. Upsample/: Upsample[-1, n_][f_] := Rev[n][f]
  2225.  
  2226.     (* convert upsample into a functional form  *)
  2227.  
  2228. Upsample/: N[Upsample[m_,n_][f_List]] := UpsampleSequence[f, m, 0]
  2229.  
  2230. Upsample/: TheFunction[Upsample[m_, n_Symbol][f_List]] :=
  2231.         UpsampleSequence[f, m, 0]
  2232. Upsample/: TheFunction[Upsample[m_, n_Symbol][f_]] :=
  2233.         UpsampledFunction[m, 0, n, TheFunction[f] /. n -> n / m]
  2234. Upsample/: TheFunction[Upsample[m_, n_List][f_]] :=
  2235.         UpsampledFunction[ m, 0, n,
  2236.             TheFunction[f] /. ReplaceWith[n, Inverse[m] . n] ]
  2237.  
  2238.     (* extent of upsampled function  *)
  2239.  
  2240. Upsample/: Extent1D[ Upsample[m_, n_][f_], n_ ] := m Extent1D[f, n]
  2241.  
  2242.     (* formatting of the upsample operator *)
  2243.  
  2244. Upsample/: Format[ Upsample[m_, n_List] ] :=
  2245.     Block [    {bar},
  2246.         bar = TableForm[ Table[ "  |  ", Release[Dimensions[n]] ] ];
  2247.         Format[ SequenceForm[ Upsample,
  2248.                       Subscript[ TableForm[m] ],
  2249.                       Subscript[ bar ],
  2250.                       Subscript[ TableForm[n] ] ] ] ]
  2251. Upsample/: Format[ Upsample[m_, n_] ] :=
  2252.         Format[ Subscripted[Upsample[m, n]] ]
  2253.  
  2254. Upsample/: Format[ Upsample, TeXForm ] := "\\uparrow"
  2255. Upsample/: Format[ Upsample[m_, n_], TeXForm ] :=
  2256.         inTeXformat[ Upsample, m, n ]
  2257.  
  2258. Upsample/: GetOperatorVariables[ Upsample[l_, n_] ] := n
  2259.  
  2260. (*  UpsampledFunction  *)
  2261. lastMatrix = Null
  2262. lastMatrixInverse = Null
  2263.  
  2264. integerVectorQ[x_] := Apply[ And, Map[ IntegerQ, x ] ]
  2265.  
  2266. UpsampledFunction[m_?NumberQ, l_, n_?NumberQ, f_] :=
  2267.     If [ IntegerQ[Rationalize[n / m]], f, l ]
  2268.  
  2269. UpsampledFunction[m_List, l_, n_List, f_] :=
  2270.     Block [    {minv, mmatrix, nvector, retval},
  2271.         retval = l;
  2272.         nvector = Rationalize[n];
  2273.         If [ integerVectorQ[ nvector ],
  2274.              mmatrix = Rationalize[m];
  2275.              minv = If [ SameQ[mmatrix, lastMatrix],
  2276.                  lastMatrixInverse,
  2277.                  lastMatrix = mmatrix;
  2278.                  lastMatrixInverse = Inverse[mmatrix] ];
  2279.              If [ integerVectorQ[minv . nvector], retval = f ] ];
  2280.         retval ] /;
  2281.     Apply[ And, Map[ NumberQ, n ] ] && MatrixQ[m]
  2282.  
  2283. (*  UpsampleFactor --  must be independent of variable z  *)
  2284. UpsampleFactor[f_, z_, extractor_:GetAllExponents] :=
  2285.     Block [    {ratgcd},
  2286.         If [ FreeQ[f, z], Return[0] ];
  2287.         ratgcd = Apply[ RationalGCD, extractor[f, z] ];
  2288.         ratgcd = discBreakup[ratgcd, z];
  2289.         If [ IntegerQ[ratgcd],
  2290.              ratgcd,
  2291.              Numerator[ratgcd] ] ]
  2292.  
  2293. (*  UpsampleSequence  *)
  2294. UpsampleSequence[seq_, m_:2, fill_:0] :=
  2295.     Block [    {fillcount, input, len, newseq},
  2296.  
  2297.         len = Length[seq];
  2298.         newseq = List[ seq[[1]] ];
  2299.  
  2300.         (*  Build the new sequence newseq by appending
  2301.             m - 1 fill elements and then by appending
  2302.             a value from the original sequence.  *)
  2303.  
  2304.         For [ input = 2, input <= len, input++,
  2305.               For [ fillcount = 1, fillcount < m, fillcount++,
  2306.                 AppendTo[newseq, fill] ];
  2307.               AppendTo[newseq, seq[[input]] ] ];
  2308.  
  2309.         newseq ]  /;
  2310.     IntegerQ[m] && ( m >= 2 )
  2311.  
  2312. (*  Z  *)
  2313. Z/: Z[n_] := Z[n, DummyVariables[Length[n], Global`z]]
  2314. Z/: Z[n_, z_] [ InvZ[zi_, n_] [f_] ] := 
  2315.     If [ SameQ[z, zi], f, f /. ReplaceWith[zi, z] ] /;
  2316.     Length[z] == Length[zi]
  2317.  
  2318. Z/: Z^-1[a__] := InvZ[a]
  2319.  
  2320. Z/: Format[ Z, TeXForm ] := "{\\cal Z}"
  2321. Z/: Format[ Z[n_, z_], TeXForm ] := StringForm[ "{\\cal Z}_{``}", n ]
  2322.  
  2323. (*  E N D     P A C K A G E  *)
  2324.  
  2325. End[]
  2326. EndPackage[]
  2327.  
  2328.  
  2329. (*  A L I A S E S  *)
  2330.  
  2331. Unprotect[ { AliasedSinc, AliasSinc, ASinc } ]
  2332. Clear[ AliasedSinc, AliasSinc, ASinc ]
  2333. AliasedSinc = Dirichlet
  2334. AliasedSinc::usage = Dirichlet::usage
  2335. AliasSinc = Dirichlet
  2336. AliasSinc::usage = Dirichlet::usage
  2337. ASinc = Dirichlet
  2338. ASinc::usage = Dirichlet::usage
  2339. Protect[ { AliasedSinc, AliasSinc, ASinc } ]
  2340.  
  2341. If [ TrueQ[ $VersionNumber >= 2.0 ],
  2342.      On[ General::spell ];
  2343.      On[ General::spell1 ] ]
  2344.  
  2345.  
  2346. (*  H E L P     I N F O R M A T I O N  *)
  2347.  
  2348. Block [    {newfuns},
  2349.     newfuns = 
  2350.       { DeltaIntegrate,      DeltaPlot,        DiscreteGraphics,
  2351.         Extent1D,          DummyVariables,    GetDeltaFunctions,
  2352.         IntervalsToFunction,  OperatorInOperExpr,    OperatorName,
  2353.         ParametersInOperExpr, ScalingFactor,    SequencePlot,
  2354.         SequenceToFunction,   SignalPlot,        SignalsInOperExpr,
  2355.         "Signum",          SPSimplify,        TheFunction,
  2356.         ToContinuous,      ToDiscrete,        UpsampledFunction,
  2357.         UpsampleFactor,      UpsampleSequence };
  2358.     Combine[ SPfunctions, newfuns ];
  2359.     Apply[ Protect, newfuns ] ]
  2360.  
  2361. Block [    {newoperators},
  2362.     newoperators =
  2363.       { CConvolve,        CircularShift,
  2364.         Convolve,        DFT,              Difference,
  2365.         Downsample,        DTFT,            FT,
  2366.         Interleave,        InvDFT,            InvDTFT,
  2367.         InvFT,        InvL,            InvZ,
  2368.         L,            PolyphaseDownsample,    PolyphaseUpsample,
  2369.         Periodic,        Rev,              RewriteSummations,
  2370.         ScaleAxis,        Shift,              Summation,
  2371.         Upsample,        Z };
  2372.     Combine[ SPoperators, newoperators ];
  2373.     Apply[ Protect, newoperators ] ]
  2374.  
  2375. Block [    {newsignals},
  2376.     newsignals =
  2377.       { "AliasSinc",    "ASinc",        CPulse,
  2378.         CStep,        Delta,            Dirichlet,
  2379.         Impulse,        LineImpulse,        Pulse,
  2380.         Sinc,        Step,            Unit };
  2381.     Combine[ SPsignals, newsignals ];
  2382.     Apply[ Protect, newsignals ] ]
  2383.  
  2384.  
  2385.  
  2386. (* Under Mma 2.0, Delta is used by Integrate *)
  2387. If [ TrueQ[ $VersionNumber >= 2.0 ], Unprotect[Delta] ]
  2388.  
  2389. (*    When encoded using ":=", these next rules causes Simplify to   *)
  2390. (*  carry out incorrect simplifications when an expression contains  *)
  2391. (*  an Impulse term and a term containing 1/n because Simplify will  *)
  2392. (*  group the expression over a common denominator thereby putting   *)
  2393. (*  the n in front of Impulse[n] which whould force it to zero,      *)
  2394. (*  thereby eliminating a perfectly valid term.                 *)
  2395.  
  2396. Unprotect[ SPSimplificationRules ]
  2397. AppendTo[ SPSimplificationRules,
  2398.       ( f_ Impulse[n_Symbol + m_.] :> (f /. n -> -m) Impulse[n + m] /;
  2399.         NumberQ[m] && ! FreeQ[f, n] ) ]
  2400. AppendTo[ SPSimplificationRules, ( x_ Sinc[b_. x_] :> Sin[b x] / b ) ]
  2401. AppendTo[ SPSimplificationRules, ( Sinc[-x_] :> Sinc[x] ) ]
  2402. AppendTo[ SPSimplificationRules, ( Delta[-x_] :> Delta[x] ) ]
  2403. AppendTo[ SPSimplificationRules, ( Delta[a_?Positive x_] :> Delta[x] / a ) ]
  2404. AppendTo[ SPSimplificationRules, ( Impulse[-x_] :> Impulse[x] ) ]
  2405. AppendTo[ SPSimplificationRules, ( CPulse[L_, L_ - x_] :> CPulse[L, x] ) ]
  2406.  
  2407. (*  Simplifications when an impulse is the input      *)
  2408.  
  2409. AppendTo[ SPSimplificationRules,
  2410.       ( Downsample[L_, n_][a_. Impulse[n_]] :> a Impulse[n] ) ]
  2411. AppendTo[ SPSimplificationRules,
  2412.       ( Upsample[L_, n_][a_. Impulse[n_]] :> a Impulse[n] ) ]
  2413.  
  2414. (*  Simplifications when an exponential is the input  *)
  2415.  
  2416. AppendTo[ SPSimplificationRules,
  2417.       ( Rev[n_Symbol][Exp[ Complex[0, a_] b_. n_ ] ] :>
  2418.         Exp[-I a b n] ) ]
  2419. AppendTo[ SPSimplificationRules,
  2420.       ( ScaleAxis[l_,w_Symbol][Exp[Complex[0, a_] b_. w_]] :>
  2421.         Exp[I a b w l] ) ]
  2422.  
  2423. (*  Other simplifications:  when these are encoded    *)
  2424. (*  using ":=", they can cause rules in some of the   *)
  2425. (*  packages to confuse Mathematica to no end.  For   *)
  2426. (*  example, hard wiring these rules will cause       *)
  2427. (*  the "RewriteRules.m" package to hang.             *)
  2428. AppendTo[ SPSimplificationRules,
  2429.       ( Difference[k_, n_][c_] :> 0 /; MyFreeQ[c,n] ) ]
  2430. AppendTo[ SPSimplificationRules,
  2431.       ( Downsample[m_, n_][c_] :> c /; MyFreeQ[c, n] ) ]
  2432. AppendTo[ SPSimplificationRules,
  2433.       ( Periodic[k_,n_][x_] :> x /; MyFreeQ[x, n] ) ]
  2434. AppendTo[ SPSimplificationRules,
  2435.       ( Rev[n_][x_] :> x /; MyFreeQ[x, n] ) ]
  2436. AppendTo[ SPSimplificationRules,
  2437.       ( ScaleAxis[l_, w_][c_] :> c /; MyFreeQ[c, w] ) ]
  2438. AppendTo[ SPSimplificationRules,
  2439.       ( Shift[m_, n_][x_] :> x /; MyFreeQ[x, n] ) ]
  2440. AppendTo[ SPSimplificationRules,
  2441.       ( Summation[k_, rest___][a_ x_] :> a Summation[k, rest][x] /;
  2442.         FreeQ[a, k] ) ]
  2443.  
  2444. Protect[ SPSimplificationRules ]
  2445.  
  2446.  
  2447. (*  E N D     M E S S A G E  *)
  2448.  
  2449. Print["The knowledge base of signal processing operators has been loaded."]
  2450. Null
  2451.  
  2452.